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
Qt: resizing a QLabel containing a QPixmap while keeping its aspect ratio
提问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 QSizePolicy
and sizeHint()
of the QLabel to resize the QPixmap while keeping the aspect ratio of the original QPixmap?
如何修改QLabel的QSizePolicy
和sizeHint()
以调整 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
resizeEvent
of 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 contentsMargin
to 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 AspectRatioPixmapLabel
class, 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, becauseQLabel
actually callsupdateGeometry
insidesetPixmap
, which may trigger resize events... heightForWidth
seemed to be ignored by the containing widget (aQScrollArea
in my case) until I started setting a size policy for the label, explicitly callingpolicy.setHeightForWidth(true)
- I want the label to never grow more than the original pixmap size
QLabel
's implementation ofminimumSizeHint()
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
实际上调用了updateGeometry
insidesetPixmap
,这可能会触发调整大小事件... 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 QLabel
handle 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 设置“首选”大小有什么建议,以便它在首次启动应用程序时不采用最大分辨率?