Używam QLabel do wyświetlania użytkownikowi zawartości większej, dynamicznie zmieniającej się mapy QPixmap. Byłoby miło, gdyby ta etykieta była mniejsza / większa w zależności od dostępnego miejsca. Rozmiar ekranu nie zawsze jest tak duży jak QPixmap.
Jak mogę zmodyfikować QSizePolicy
i sizeHint()
etykiety QLabel, aby zmienić rozmiar mapy QPixmap, zachowując jednocześnie proporcje oryginalnej QPixmap?
Nie mogę modyfikować sizeHint()
QLabel, ustawienie na minimumSize()
zero nie pomaga. Ustawienie hasScaledContents()
na QLabel pozwala na rozwój, ale psuje proporcje ...
Tworzenie podklas QLabel pomogło, ale to rozwiązanie dodaje zbyt dużo kodu dla prostego problemu ...
Jakieś sprytne wskazówki, jak to osiągnąć bez tworzenia podklas?
QLabel
w aktualnym układzie.QPixmap
Powinny zachować swój rozmiar, treść i wymiar. Byłoby również miło, gdyby zmiana rozmiaru (w rzeczywistości zmniejszanie się) następowała „automagicznie”, aby wypełnić dostępne miejsce - do rozmiaru oryginałuQPixmap
. Wszystko to zostało zrobione przez podklasy ...Odpowiedzi:
Aby zmienić rozmiar etykiety, możesz wybrać odpowiednią zasadę rozmiaru dla etykiety, taką jak rozwijanie lub minimalne rozwinięcie.
Możesz skalować piksmapę, zachowując jej proporcje przy każdej zmianie:
QPixmap p; // load pixmap // get label dimensions int w = label->width(); int h = label->height(); // set a scaled pixmap to a w x h window keeping its aspect ratio label->setPixmap(p.scaled(w,h,Qt::KeepAspectRatio));
Są dwa miejsca, w których powinieneś dodać ten kod:
resizeEvent
widgecie zawierającym etykietęźródło
QLabel
. Ale pomyślałem, że ten przypadek użycia (wyświetlanie obrazów o dowolnym rozmiarze w widżetach o dowolnym rozmiarze) byłby na tyle powszechny, że miałby coś podobnego do zaimplementowania za pomocą istniejącego kodu ...QLabel
. W przeciwnym razie możesz użyć kodu mojej odpowiedzi w slocie / funkcji, która będzie wywoływana za każdym razem, gdy mapa pikseli się zmieni.QLabel
automagicznie rozszerzać się w oparciu o zmianę rozmiaru użytkownikówQMainWindow
i dostępnej przestrzeni, nie mogę użyć rozwiązania sygnału / gniazda - nie mogę w ten sposób modelować rozszerzającej się polityki.label->setMinimumSize(1, 1)
Dopracowałem tę brakującą podklasę
QLabel
. Jest niesamowity i działa dobrze.aspektratiopixmaplabel.h
#ifndef ASPECTRATIOPIXMAPLABEL_H #define ASPECTRATIOPIXMAPLABEL_H #include <QLabel> #include <QPixmap> #include <QResizeEvent> class AspectRatioPixmapLabel : public QLabel { Q_OBJECT public: explicit AspectRatioPixmapLabel(QWidget *parent = 0); virtual int heightForWidth( int width ) const; virtual QSize sizeHint() const; QPixmap scaledPixmap() const; public slots: void setPixmap ( const QPixmap & ); void resizeEvent(QResizeEvent *); private: QPixmap pix; }; #endif // ASPECTRATIOPIXMAPLABEL_H
aspektratiopixmaplabel.cpp
#include "aspectratiopixmaplabel.h" //#include <QDebug> AspectRatioPixmapLabel::AspectRatioPixmapLabel(QWidget *parent) : QLabel(parent) { this->setMinimumSize(1,1); setScaledContents(false); } void AspectRatioPixmapLabel::setPixmap ( const QPixmap & p) { pix = p; QLabel::setPixmap(scaledPixmap()); } int AspectRatioPixmapLabel::heightForWidth( int width ) const { return pix.isNull() ? this->height() : ((qreal)pix.height()*width)/pix.width(); } QSize AspectRatioPixmapLabel::sizeHint() const { int w = this->width(); return QSize( w, heightForWidth(w) ); } QPixmap AspectRatioPixmapLabel::scaledPixmap() const { return pix.scaled(this->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation); } void AspectRatioPixmapLabel::resizeEvent(QResizeEvent * e) { if(!pix.isNull()) QLabel::setPixmap(scaledPixmap()); }
Mam nadzieję, że to pomoże! (Zaktualizowano
resizeEvent
, zgodnie z odpowiedzią @ dmzl)źródło
QLabel::setPixmap(pix.scaled(this->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation));
dosetPixmap()
metody.this->resize(width(), height());
na końcusetPixmap
funkcji.auto scaled = pix.scaled(this->size() * devicePixelRatioF(), Qt::KeepAspectRatio, Qt::SmoothTransformation); scaled.setDevicePixelRatio(devicePixelRatioF()); return scaled;
Działa to również na ekranach o normalnej skali.Po prostu używam,
contentsMargin
aby naprawić współczynnik proporcji.#pragma once #include <QLabel> class AspectRatioLabel : public QLabel { public: explicit AspectRatioLabel(QWidget* parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags()); ~AspectRatioLabel(); public slots: void setPixmap(const QPixmap& pm); protected: void resizeEvent(QResizeEvent* event) override; private: void updateMargins(); int pixmapWidth = 0; int pixmapHeight = 0; };
#include "AspectRatioLabel.h" AspectRatioLabel::AspectRatioLabel(QWidget* parent, Qt::WindowFlags f) : QLabel(parent, f) { } AspectRatioLabel::~AspectRatioLabel() { } void AspectRatioLabel::setPixmap(const QPixmap& pm) { pixmapWidth = pm.width(); pixmapHeight = pm.height(); updateMargins(); QLabel::setPixmap(pm); } void AspectRatioLabel::resizeEvent(QResizeEvent* event) { updateMargins(); QLabel::resizeEvent(event); } void AspectRatioLabel::updateMargins() { if (pixmapWidth <= 0 || pixmapHeight <= 0) return; int w = this->width(); int h = this->height(); if (w <= 0 || h <= 0) return; if (w * pixmapHeight > h * pixmapWidth) { int m = (w - (pixmapWidth * h / pixmapHeight)) / 2; setContentsMargins(m, 0, m, 0); } else { int m = (h - (pixmapHeight * w / pixmapWidth)) / 2; setContentsMargins(0, m, 0, m); } }
Jak na razie działa idealnie dla mnie. Nie ma za co.
źródło
QSize
zamiast...Width
i...Height
? Jeśli nic innego, to sprawiłoby, że twoje przedterminowe sprawdzenia byłyby prostymQSize::isEmpty
wezwaniem.QPixmap
iQWidget
obie mająsize
metody pobierania szerokości i wysokości jako plikuQSize
.Próbowałem użyć
AspectRatioPixmapLabel
klasy Phyatta , ale napotkałem kilka problemów:QLabel::setPixmap(...)
wewnątrz metody resizeEvent, ponieważ wQLabel
rzeczywistości wywołaniaupdateGeometry
wewnątrzsetPixmap
, co może wywołać zdarzenia zmiany rozmiaru ...heightForWidth
wydawało się być ignorowane przez widżet zawierający (aQScrollArea
w moim przypadku), dopóki nie zacząłem ustawiać polityki rozmiaru dla etykiety, wyraźnie wywołującpolicy.setHeightForWidth(true)
QLabel
ImplementacjaminimumSizeHint()
robi trochę magii dla etykiet zawierających tekst, ale zawsze resetuje politykę rozmiaru do domyślnej, więc musiałem ją nadpisaćTo powiedziawszy, oto moje rozwiązanie. Odkryłem, że mogę po prostu użyć
setScaledContents(true)
i pozwolićQLabel
sobie na zmianę rozmiaru. Oczywiście zależy to od widżetu / układu zawierającego rozszerzenieheightForWidth
.aspektratiopixmaplabel.h
#ifndef ASPECTRATIOPIXMAPLABEL_H #define ASPECTRATIOPIXMAPLABEL_H #include <QLabel> #include <QPixmap> class AspectRatioPixmapLabel : public QLabel { Q_OBJECT public: explicit AspectRatioPixmapLabel(const QPixmap &pixmap, QWidget *parent = 0); virtual int heightForWidth(int width) const; virtual bool hasHeightForWidth() { return true; } virtual QSize sizeHint() const { return pixmap()->size(); } virtual QSize minimumSizeHint() const { return QSize(0, 0); } }; #endif // ASPECTRATIOPIXMAPLABEL_H
aspektratiopixmaplabel.cpp
#include "aspectratiopixmaplabel.h" AspectRatioPixmapLabel::AspectRatioPixmapLabel(const QPixmap &pixmap, QWidget *parent) : QLabel(parent) { QLabel::setPixmap(pixmap); setScaledContents(true); QSizePolicy policy(QSizePolicy::Maximum, QSizePolicy::Maximum); policy.setHeightForWidth(true); this->setSizePolicy(policy); } int AspectRatioPixmapLabel::heightForWidth(int width) const { if (width > pixmap()->width()) { return pixmap()->height(); } else { return ((qreal)pixmap()->height()*width)/pixmap()->width(); } }
źródło
heightForWidth
właściwość, ta odpowiedź zawodzi w ogólnym przypadku, w którym widżet nadrzędny i / lub układ zawierający tę etykietę nie respektująheightForWidth
właściwości. Które jest niefortunne, ponieważ w przeciwnym razie odpowiedź jest korzystne phyatt „s dawna odpowiedź .Zaadaptowano z Timmmm do PYQT5
from PyQt5.QtGui import QPixmap from PyQt5.QtGui import QResizeEvent from PyQt5.QtWidgets import QLabel class Label(QLabel): def __init__(self): super(Label, self).__init__() self.pixmap_width: int = 1 self.pixmapHeight: int = 1 def setPixmap(self, pm: QPixmap) -> None: self.pixmap_width = pm.width() self.pixmapHeight = pm.height() self.updateMargins() super(Label, self).setPixmap(pm) def resizeEvent(self, a0: QResizeEvent) -> None: self.updateMargins() super(Label, self).resizeEvent(a0) def updateMargins(self): if self.pixmap() is None: return pixmapWidth = self.pixmap().width() pixmapHeight = self.pixmap().height() if pixmapWidth <= 0 or pixmapHeight <= 0: return w, h = self.width(), self.height() if w <= 0 or h <= 0: return if w * pixmapHeight > h * pixmapWidth: m = int((w - (pixmapWidth * h / pixmapHeight)) / 2) self.setContentsMargins(m, 0, m, 0) else: m = int((h - (pixmapHeight * w / pixmapWidth)) / 2) self.setContentsMargins(0, m, 0, m)
źródło
Dokumentacja Qt zawiera przykład przeglądarki obrazów, który demonstruje obsługę zmiany rozmiaru obrazów w pliku
QLabel
. Podstawową ideą jest użycieQScrollArea
jako kontenera doQLabel
użytku,label.setScaledContents(bool)
aw razie potrzeby,scrollarea.setWidgetResizable(bool)
do wypełnienia dostępnej przestrzeni i / lub zapewnienia możliwości zmiany rozmiaru QLabel w środku. Dodatkowo, aby zmienić rozmiar QLabel z zachowaniem proporcji:Opcje
width
iheight
można ustawić na podstawiescrollarea.width()
iscrollarea.height()
. W ten sposób nie ma potrzeby tworzenia podklasy QLabel.źródło