Utilizo QLabel para mostrar al usuario el contenido de un QPixmap más grande que cambia dinámicamente. Sería bueno hacer esta etiqueta más pequeña / más grande según el espacio disponible. El tamaño de la pantalla no siempre es tan grande como el QPixmap.
¿Cómo puedo modificar QSizePolicy
y sizeHint()
de QLabel para cambiar el tamaño del QPixmap manteniendo la relación de aspecto del QPixmap original?
No puedo modificar sizeHint()
el QLabel, establecer el minimumSize()
en cero no ayuda. La configuración hasScaledContents()
en QLabel permite crecer, pero rompe la relación de aspecto ...
Subclasificar QLabel ayudó, pero esta solución agrega demasiado código para un simple problema ...
¿Algún consejo inteligente sobre cómo lograr esto sin subclases?
QLabel
diseño actual. ElQPixmap
debe mantener su tamaño, contenido y dimensión. Además, sería bueno que el cambio de tamaño (encogiéndose en realidad) ocurra "automágicamente" para llenar el espacio disponible, hasta el tamaño del originalQPixmap
. Todo esto se hizo mediante subclases ...Respuestas:
Para cambiar el tamaño de la etiqueta, puede seleccionar una política de tamaño adecuada para la etiqueta, como expansión o expansión mínima.
Puede escalar el mapa de píxeles manteniendo su relación de aspecto cada vez que cambia:
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));
Hay dos lugares donde debe agregar este código:
resizeEvent
del widget que contiene la etiquetafuente
QLabel
. Pero pensé que este caso de uso (que muestra imágenes con tamaño arbitrario en widgets de tamaño arbitrario) sería lo suficientemente común como para tener algo así implementable a través del código existente ...QLabel
. De lo contrario, puede usar el código de mi respuesta en una ranura / función que se llamará cada vez que cambie el mapa de píxeles.QLabel
que se expanda automáticamente en función del cambio de tamaño de los usuariosQMainWindow
y el espacio disponible, no puedo usar la solución de señal / ranura; no puedo modelar una política de expansión de esta manera.label->setMinimumSize(1, 1)
He pulido esta subclase faltante de
QLabel
. Es impresionante y funciona bien.Aspectratiopixmaplabel.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
Aspectratiopixmaplabel.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()); }
¡Espero que ayude! (Actualizado
resizeEvent
, según la respuesta de @ dmzl)fuente
QLabel::setPixmap(pix.scaled(this->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation));
alsetPixmap()
método.this->resize(width(), height());
al final de lasetPixmap
función.auto scaled = pix.scaled(this->size() * devicePixelRatioF(), Qt::KeepAspectRatio, Qt::SmoothTransformation); scaled.setDevicePixelRatio(devicePixelRatioF()); return scaled;
Esto también funciona en pantallas normalmente escaladas.Solo uso
contentsMargin
para arreglar la relación de aspecto.#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); } }
Funciona perfectamente para mí hasta ahora. De nada.
fuente
QSize
lugar de...Width
y...Height
? Si nada más, eso haría que sus cheques de devolución anticipada fueran una simpleQSize::isEmpty
llamada.QPixmap
yQWidget
ambos tienensize
métodos para recuperar el ancho y el alto como unQSize
.Intenté usar la
AspectRatioPixmapLabel
clase de phyatt , pero experimenté algunos problemas:QLabel::setPixmap(...)
Rastreé esto hasta la llamada de dentro del método resizeEvent, porque enQLabel
realidad las llamadasupdateGeometry
dentrosetPixmap
, lo que puede desencadenar eventos de cambio de tamaño ...heightForWidth
parecía ser ignorado por el widget contenedor (aQScrollArea
en mi caso) hasta que comencé a configurar una política de tamaño para la etiqueta, llamando explícitamentepolicy.setHeightForWidth(true)
QLabel
La implementación deminimumSizeHint()
hace algo de magia para las etiquetas que contienen texto, pero siempre restablece la política de tamaño a la predeterminada, así que tuve que sobrescribirlaDicho esto, aquí está mi solución. Descubrí que podía usar
setScaledContents(true)
y dejarQLabel
manejar el cambio de tamaño. Por supuesto, esto depende del widget / diseño que lo contenga respetando elheightForWidth
.Aspectratiopixmaplabel.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
Aspectratiopixmaplabel.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(); } }
fuente
heightForWidth
propiedad, esta respuesta falla para el caso general en el que el widget principal y / o el diseño que contiene esta etiqueta no respetan laheightForWidth
propiedad. Lo cual es lamentable, ya que esta respuesta es preferible a la respuesta de larga data de phyatt .Adaptado de Timmmm a 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)
fuente
La documentación de Qt tiene un ejemplo de Visor de imágenes que demuestra cómo manejar imágenes de cambio de tamaño dentro de un archivo
QLabel
. La idea básica es utilizarQScrollArea
como un contenedor para elQLabel
y si es necesario, utilicelabel.setScaledContents(bool)
yscrollarea.setWidgetResizable(bool)
para llenar el espacio disponible y / o garantizar QLabel interior es de tamaño variable. Además, para cambiar el tamaño de QLabel respetando la relación de aspecto, utilice:El
width
yheight
se puede establecer basándose enscrollarea.width()
yscrollarea.height()
. De esta manera, no es necesario crear una subclase de QLabel.fuente