Я использую QLabel для отображения пользователю содержимого более крупного, динамически изменяющегося QPixmap. Было бы неплохо сделать эту этикетку меньше / больше в зависимости от доступного места. Размер экрана не всегда такой большой, как у QPixmap.
Как я могу изменить QSizePolicy
и sizeHint()
QLabel, чтобы изменить размер QPixmap, сохраняя соотношение сторон исходного QPixmap?
Я не могу изменить sizeHint()
QLabel, установка minimumSize()
нуля не помогает. Настройка hasScaledContents()
в QLabel позволяет расти, но нарушает соотношение сторон ...
Создание подкласса QLabel действительно помогло, но это решение добавляет слишком много кода для простой проблемы ...
Есть какие-нибудь умные подсказки, как этого добиться без подкласса?
QLabel
в текущем макете. ОнQPixmap
должен сохранять свой размер, содержание и размер. Кроме того, было бы хорошо, если бы изменение размера (сжатие в реальности) происходило «автоматически», чтобы заполнить доступное пространство - до размера оригиналаQPixmap
. Все это было сделано с помощью подклассов ...Ответы:
Чтобы изменить размер метки, вы можете выбрать подходящую политику размера для метки, например, расширение или минимальное расширение.
Вы можете масштабировать растровое изображение, сохраняя его соотношение сторон при каждом изменении:
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));
Есть два места, куда вы должны добавить этот код:
resizeEvent
виджете, содержащем меткуисточник
QLabel
. Но я думал, что этот вариант использования (отображение изображений произвольного размера в виджетах произвольного размера) будет достаточно распространенным, чтобы нечто подобное можно было реализовать с помощью существующего кода ...QLabel
. В противном случае вы можете использовать код моего ответа в слоте / функции, которая будет вызываться каждый раз при изменении растрового изображения.QLabel
чтобы он автоматически расширялся в зависимости от изменения пользователем размераQMainWindow
и доступного пространства, я не могу использовать решение сигнал / слот - я не могу смоделировать политику расширения таким образом.label->setMinimumSize(1, 1)
Я отполировал этот недостающий подкласс
QLabel
. Это потрясающе и хорошо работает.аспектratiopixmaplabel.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
аспектratiopixmaplabel.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()); }
Надеюсь, это поможет! (Обновлено
resizeEvent
, согласно ответу @dmzl)источник
QLabel::setPixmap(pix.scaled(this->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation));
поsetPixmap()
методу добавил .this->resize(width(), height());
концеsetPixmap
.auto scaled = pix.scaled(this->size() * devicePixelRatioF(), Qt::KeepAspectRatio, Qt::SmoothTransformation); scaled.setDevicePixelRatio(devicePixelRatioF()); return scaled;
Это также работает на экранах с нормальным масштабированием.Я просто использую,
contentsMargin
чтобы поправить соотношение сторон.#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); } }
У меня пока работает отлично. Пожалуйста.
источник
QSize
вместо...Width
и...Height
? По крайней мере, это сделало бы ваши чеки на досрочное возвращение простойQSize::isEmpty
задачей.QPixmap
и уQWidget
обоих естьsize
методы для получения ширины и высоты какQSize
.Я пробовал использовать
AspectRatioPixmapLabel
класс phyatt , но столкнулся с несколькими проблемами:QLabel::setPixmap(...)
внутри метода resizeEvent, потому что наQLabel
самом деле вызываетupdateGeometry
внутриsetPixmap
, что может запускать события изменения размера ...heightForWidth
казалось, игнорируется содержащим виджетом (aQScrollArea
в моем случае), пока я не начал устанавливать политику размера для метки, явно вызываяpolicy.setHeightForWidth(true)
QLabel
реализацияminimumSizeHint()
делает некоторую магию для меток, содержащих текст, но всегда сбрасывает политику размера на значение по умолчанию, поэтому мне пришлось перезаписать ееТем не менее, вот мое решение. Я обнаружил, что могу просто использовать
setScaledContents(true)
и позволитьQLabel
изменять размер. Конечно, это зависит от содержащегося в нем виджета / макета, поддерживающегоheightForWidth
.аспектratiopixmaplabel.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
аспектratiopixmaplabel.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(); } }
источник
heightForWidth
этот ответ предпочтительнее для крайних случаев, когда родительский виджет и / или макет, содержащий эту метку, соблюдает свойство, в общем случае, когда родительский виджет и / или макет, содержащий эту метку, не соблюдают свойство, этот ответ не выполняетсяheightForWidth
. Что прискорбно, так как этот ответ иначе предпочтительнее phyatt «S давний ответ .Адаптировано из Timmmm к 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)
источник
В документации Qt есть пример средства просмотра изображений, который демонстрирует обработку изменения размера изображений внутри файла
QLabel
. Основная идея состоит в том, чтобы использоватьQScrollArea
в качестве контейнера дляQLabel
и, если необходимо, использоватьlabel.setScaledContents(bool)
иscrollarea.setWidgetResizable(bool)
заполнить доступное пространство и / или обеспечить возможность изменения размера QLabel внутри. Кроме того, чтобы изменить размер QLabel с учетом соотношения сторон, используйте:width
Иheight
может быть установлен на основеscrollarea.width()
иscrollarea.height()
. Таким образом, нет необходимости создавать подклассы QLabel.источник