Ich verwende ein QLabel, um dem Benutzer den Inhalt einer größeren, sich dynamisch ändernden QPixmap anzuzeigen. Es wäre schön, dieses Etikett je nach verfügbarem Platz kleiner / größer zu machen. Die Bildschirmgröße ist nicht immer so groß wie die QPixmap.
Wie kann ich das QSizePolicy
und sizeHint()
des QLabels ändern, um die Größe der QPixmap zu ändern, während das Seitenverhältnis der ursprünglichen QPixmap beibehalten wird?
Ich kann sizeHint()
das QLabel nicht ändern , das Setzen minimumSize()
auf Null hilft nicht. Das Einstellen hasScaledContents()
auf dem QLabel ermöglicht das Wachsen, bricht aber das Seitenverhältnis ...
Die Unterklasse von QLabel hat geholfen, aber diese Lösung fügt zu viel Code für nur ein einfaches Problem hinzu ...
Irgendwelche intelligenten Hinweise, wie dies ohne Unterklassen erreicht werden kann?
QLabel
im aktuellen Layout. DerQPixmap
sollte seine Größe, Inhalt und Dimension behalten. Es wäre auch schön, wenn die Größenänderung (in der Realität schrumpfen) "automatisch" erfolgt, um den verfügbaren Speicherplatz auszufüllen - bis zur Größe des OriginalsQPixmap
. All dies wurde über Unterklassen gemacht ...Antworten:
Um die Etikettengröße zu ändern, können Sie eine geeignete Größenrichtlinie für das Etikett auswählen, z. B. das Erweitern oder das minimale Erweitern.
Sie können die Pixmap skalieren, indem Sie das Seitenverhältnis bei jeder Änderung beibehalten:
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));
Es gibt zwei Stellen, an denen Sie diesen Code hinzufügen sollten:
resizeEvent
Widget, das die Beschriftung enthältquelle
QLabel
. Aber ich dachte, dieser Anwendungsfall (Bilder mit beliebiger Größe in Widgets beliebiger GrößeQLabel
. Andernfalls können Sie den Code meiner Antwort in einem Slot / einer Funktion verwenden, der jedes Mal aufgerufen wird, wenn sich die Pixmap ändert.QLabel
System basierend auf der Größe des BenutzersQMainWindow
und dem verfügbaren Speicherplatz automatisch erweitert wird, kann ich die Signal- / Slot-Lösung nicht verwenden. Auf diese Weise kann ich keine Erweiterungsrichtlinie modellieren .label->setMinimumSize(1, 1)
Ich habe diese fehlende Unterklasse von poliert
QLabel
. Es ist großartig und funktioniert gut.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()); }
Hoffentlich hilft das! (Aktualisiert
resizeEvent
gemäß der Antwort von @ dmzl)quelle
QLabel::setPixmap(pix.scaled(this->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation));
zursetPixmap()
Methode hinzufügen .this->resize(width(), height());
das Ende dersetPixmap
Funktion einfügen .auto scaled = pix.scaled(this->size() * devicePixelRatioF(), Qt::KeepAspectRatio, Qt::SmoothTransformation); scaled.setDevicePixelRatio(devicePixelRatioF()); return scaled;
Dies funktioniert auch auf normal skalierten Bildschirmen.Ich benutze nur
contentsMargin
, um das Seitenverhältnis zu korrigieren.#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); } }
Funktioniert bisher perfekt für mich. Bitte.
quelle
QSize
anstelle von...Width
und zu verwenden...Height
? Wenn nichts anderes, würde dies Ihre frühzeitige Rückgabe zu einem einfachenQSize::isEmpty
Anruf machen.QPixmap
undQWidget
beide habensize
Methoden, um die Breite und Höhe als abzurufenQSize
.Ich habe versucht, Phyatt's
AspectRatioPixmapLabel
Klasse zu verwenden, hatte aber einige Probleme:QLabel::setPixmap(...)
inside der resizeEvent-Methode zurückgeführt, daQLabel
tatsächlichupdateGeometry
inside aufgerufen wirdsetPixmap
, was Größenänderungsereignisse auslösen kann ...heightForWidth
schien vom enthaltenen Widget (QScrollArea
in meinem Fall a) ignoriert zu werden, bis ich anfing, eine Größenrichtlinie für das Etikett festzulegen und explizit aufzurufenpolicy.setHeightForWidth(true)
QLabel
Die Implementierung vonminimumSizeHint()
bewirkt etwas Magie für Beschriftungen, die Text enthalten, setzt jedoch die Größenrichtlinie immer auf die Standardrichtlinie zurück, sodass ich sie überschreiben mussteDas heißt, hier ist meine Lösung. Ich stellte fest, dass ich die Größenänderung einfach verwenden
setScaledContents(true)
und durchführen lassen konnteQLabel
. Dies hängt natürlich davon ab, welches Widget / Layout das enthältheightForWidth
.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(); } }
quelle
heightForWidth
Eigenschaft respektieren , schlägt diese Antwort für den allgemeinen Fall fehl, in dem das übergeordnete Widget und / oder Layout, das diese Bezeichnung enthält, die Eigenschaft nicht respektierenheightForWidth
. Welche bedauerlich ist, da diese Antwort sonst vorzuziehen ist phyatt ‚s Antwort langjährige .Angepasst von Timmmm an 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)
quelle
Die Qt-Dokumentationen enthalten ein Image Viewer-Beispiel, das die Handhabung der Größenänderung von Bildern in a demonstriert
QLabel
. Die Grundidee besteht darin,QScrollArea
als Container für dieQLabel
und bei Bedarf zu verwendenlabel.setScaledContents(bool)
undscrollarea.setWidgetResizable(bool)
den verfügbaren Platz zu füllen und / oder sicherzustellen, dass die Größe von QLabel im Inneren geändert werden kann. Um die Größe von QLabel zu ändern und gleichzeitig das Seitenverhältnis zu berücksichtigen, verwenden Sie außerdem:Das
width
undheight
kann basierend aufscrollarea.width()
und eingestellt werdenscrollarea.height()
. Auf diese Weise muss QLabel nicht in Unterklassen unterteilt werden.quelle