C++ Qt:调整包含 QPixmap 的 QLabel 的大小,同时保持其纵横比

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8211982/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 18:11:03  来源:igfitidea点击:

Qt: resizing a QLabel containing a QPixmap while keeping its aspect ratio

c++qtqt4qlabel

提问by marvin2k

I use a QLabel to display the content of a bigger, dynamically changing QPixmap to the user. It would be nice to make this label smaller/larger depending on the space available. The screen size is not always as big as the QPixmap.

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

How can I modify the QSizePolicyand sizeHint()of the QLabel to resize the QPixmap while keeping the aspect ratio of the original QPixmap?

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

I can't modify sizeHint()of the QLabel, setting the minimumSize()to zero does not help. Setting hasScaledContents()on the QLabel allows growing, but breaks the aspect ratio thingy...

我无法修改sizeHint()QLabel,将 设置minimumSize()为零也无济于事。hasScaledContents()QLabel 上的设置允许增长,但打破了纵横比的东西......

Subclassing QLabel did help, but this solution adds too much code for just a simple problem...

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

Any smart hints how to accomplish this withoutsubclassing?

任何聪明的提示如何在没有子类化的情况下完成这个?

回答by pnezis

In order to change the label size you can select an appropriate size policy for the label like expanding or minimum expanding.

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

You can scale the pixmap by keeping its aspect ratio every time it changes:

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

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

There are two places where you should add this code:

您应该在两个地方添加此代码:

  • When the pixmap is updated
  • In the resizeEventof the widget that contains the label
  • 当像素图更新时
  • resizeEvent包含标签的小部件中

回答by phyatt

I have polished this missing subclass of QLabel. It is awesome and works well.

我已经完善了这个缺失的QLabel. 它很棒并且运行良好。

aspectratiopixmaplabel.h

纵横比像素图标签.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

纵横比图标签.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());
}

Hope that helps! (Updated resizeEvent, per @dmzl's answer)

希望有帮助!(更新resizeEvent,根据@dmzl 的回答)

回答by Timmmm

I just use contentsMarginto fix the aspect ratio.

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

Works perfectly for me so far. You're welcome.

到目前为止对我来说非常有效。别客气。

回答by Alexander Schlüter

I tried using phyatt's AspectRatioPixmapLabelclass, but experienced a few problems:

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

  • Sometimes my app entered an infinite loop of resize events. I traced this back to the call of QLabel::setPixmap(...)inside the resizeEvent method, because QLabelactually calls updateGeometryinside setPixmap, which may trigger resize events...
  • heightForWidthseemed to be ignored by the containing widget (a QScrollAreain my case) until I started setting a size policy for the label, explicitly calling policy.setHeightForWidth(true)
  • I want the label to never grow more than the original pixmap size
  • QLabel's implementation of minimumSizeHint()does some magic for labels containing text, but always resets the size policy to the default one, so I had to overwrite it
  • 有时我的应用程序会进入无限循环的调整大小事件。我将这追溯到QLabel::setPixmap(...)resizeEvent 方法内部的调用,因为QLabel实际上调用了updateGeometryinside setPixmap,这可能会触发调整大小事件...
  • heightForWidth似乎被包含的小部件(QScrollArea在我的情况下为 a)忽略,直到我开始为标签设置大小策略,明确调用policy.setHeightForWidth(true)
  • 我希望标签永远不会超过原始像素图大小
  • QLabel的实现对minimumSizeHint()包含文本的标签有一些魔力,但总是将大小策略重置为默认策略,所以我不得不覆盖它

That said, here is my solution. I found that I could just use setScaledContents(true)and let QLabelhandle the resizing. Of course, this depends on the containing widget / layout honoring the heightForWidth.

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

aspectratiopixmaplabel.h

纵横比像素图标签.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

纵横比图标签.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();
    }
}

回答by Julien M

Thanks for sharing this. Would you have any suggestions on how I can set a "preferred" size to the QPixmap so that it does not take the maximum resolution on the first launch of the application?

感谢分享这个。您对如何为 QPixmap 设置“首选”大小有什么建议,以便它在首次启动应用程序时不采用最大分辨率?