Qt:调整包含QPixmap的QLabel的大小,同时保持其宽高比

时间:2011-11-21 12:43:12

标签: c++ qt qt4 qlabel

我使用QLabel向用户显示更大,动态变化的QPixmap的内容。根据可用空间,使这个标签更小/更大会很好。屏幕尺寸并不总是与QPixmap一样大。

如何修改QLabel的QSizePolicysizeHint()以调整QPixmap的大小,同时保持原始QPixmap的宽高比?

我无法修改QLabel的sizeHint(),将minimumSize()设置为零无效。在QLabel上设置hasScaledContents()可以增长,但会打破宽高比......

子类化QLabel确实有帮助,但是这个解决方案只为一个简单的问题添加了太多的代码......

任何智能提示如何在没有子类化的情况下完成此

6 个答案:

答案 0 :(得分:78)

要更改标签尺寸,您可以为标签选择合适的尺寸政策,例如展开或最小展开。

您可以通过每次更改时保持纵横比来缩放像素图:

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

答案 1 :(得分:28)

我已经完善了QLabel这个遗漏的子类。它太棒了,效果很好。

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());
}

希望有所帮助! (根据@ dmzl的答案更新了resizeEvent

答案 2 :(得分:10)

我只是使用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);
    }
}

到目前为止对我来说非常合适。你很受欢迎。

答案 3 :(得分:5)

我尝试过使用phyatt的AspectRatioPixmapLabel课程,但遇到了一些问题:

  • 有时我的应用程序进入无限循环的调整大小事件。我将其追溯到resizeEvent方法中QLabel::setPixmap(...)的调用,因为QLabel实际调用了updateGeometry内的setPixmap,这可能会触发调整大小事件......
  • heightForWidth似乎被包含小部件(在我的情况下为QScrollArea)忽略,直到我开始为标签设置大小政策,明确调用policy.setHeightForWidth(true)
  • 我希望标签永远不会超过原始像素图大小
  • QLabel minimumSizeHint()的实施为包含文字的标签带来了一些魔力,但总是将尺寸政策重置为默认值,所以我不得不覆盖它

那就是说,这是我的解决方案。我发现我可以使用setScaledContents(true)并让QLabel处理调整大小。 当然,这取决于包含heightForWidth的小部件/布局。

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();
    }
}

答案 4 :(得分:2)

从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)

答案 5 :(得分:0)

Qt文档有一个Image Viewer example,它演示了如何处理QLabel中的图像大小调整。基本思想是使用QScrollArea作为QLabel的容器,如果需要,使用label.setScaledContents(bool)scrollarea.setWidgetResizable(bool)填充可用空间和/或确保内部的QLabel可调整大小。 此外,要在遵守宽高比的同时调整QLabel的大小,请使用:

label.setPixmap(pixmap.scaled(width, height, Qt::KeepAspectRatio, Qt::FastTransformation));

可以基于widthheight来设置scrollarea.width()scrollarea.height()。 这样,就无需继承QLabel。