我正在尝试在QT(内部标签)中创建图像,该图像会根据窗口大小的变化改变大小,但也会保持纵横比。
最好的方法是什么?
答案 0 :(得分:2)
您使用linux标记了此问题。我在Windows 10上开发 - 离我最近的Linux是cygwin。因此,我在VS2013中解决了它,但是,嘿,这是Qt的C ++。它应该是便携式的......
实际上,QPixmap::scaled()
内置了通过保持纵横比进行缩放所需的一切。因此,我的解决方案是将QLabel
和QPixmap
插在一起相当短暂。
// standard C++ header:
#include <iostream>
#include <string>
// Qt header:
#include <QApplication>
#include <QResizeEvent>
#include <QLabel>
#include <QMainWindow>
#include <QPixmap>
#include <QTimer>
using namespace std;
class LabelImage: public QLabel {
private:
QPixmap _qPixmap, _qPixmapScaled;
public:
void setPixmap(const QPixmap &qPixmap) { setPixmap(qPixmap, size()); }
protected:
virtual void resizeEvent(QResizeEvent *pQEvent);
private:
void setPixmap(const QPixmap &qPixmap, const QSize &size);
};
void LabelImage::resizeEvent(QResizeEvent *pQEvent)
{
QLabel::resizeEvent(pQEvent);
setPixmap(_qPixmap, pQEvent->size());
}
void LabelImage::setPixmap(const QPixmap &qPixmap, const QSize &size)
{
_qPixmap = qPixmap;
_qPixmapScaled = _qPixmap.scaled(size, Qt::KeepAspectRatio);
QLabel::setPixmap(_qPixmapScaled);
}
int main(int argc, char **argv)
{
cout << QT_VERSION_STR << endl;
// main application
#undef qApp // undef macro qApp out of the way
QApplication qApp(argc, argv);
// setup GUI
QMainWindow qWin;
#if 0 // does not consider aspect ratio
QLabel qLblImg;
qLblImg.setScaledContents(true);
#else // (not) 0
LabelImage qLblImg;
#endif // 0
qLblImg.setAlignment(Qt::AlignCenter);
qLblImg.setSizePolicy(
QSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored));
QPixmap qPM;
if (qPM.load("cats.jpg")) qLblImg.setPixmap(qPM);
else {
qLblImg.setText(
QString::fromLatin1("Sorry. Cannot find file 'cats.jpg'."));
}
qWin.setCentralWidget(&qLblImg);
qWin.show();
// run application
return qApp.exec();
}
注意:
我重载了QLabel::setPixmap()
方法并实际存储了两个版本的像素图 - 原始版本和缩放版本。我不确定这是否有必要 - 这是我第一次使用QPixmap
。
在阅读Qt文档时,我发现QLabel::setScaledContents()。我试了一下,但没考虑像素图的宽高比。我找不到将其设置为额外选项的方法。 (可能是,我没有足够的搜索。我禁用了这段代码,但是把它留作“错误的方向”。)
在中间版本中,我能够放大应用程序(并且缩放很好)但我无法缩小它。谷歌搜索了一下我发现了SO: Enable QLabel to shrink even if it truncates text。这解决了这个问题。
为了保持样本简短,我对图像文件名进行了硬编码。实际上不必说应用程序的当前目录必须是文件所在的目录。 (这在Linux中可能没有问题,但我必须适当调整VS2013中的调试设置。)
以下是我的测试应用的快照:
这应该(当然)可以加载到Qt中的任何图像文件。但是,为了使样本完整(并且因为互联网和猫的照片真的在一起),我也提供了样本图像(供下载)。
左边是马克斯,右边是莫里茨。 (反之亦然?)
编辑:
根据Shefy Gur-ary的反馈,这在QLayout
中无效。因此,我修改了原始版本并在我的示例代码中添加了QGridLayout
来检查此主题:
// standard C++ header:
#include <iostream>
#include <string>
// Qt header:
#include <QApplication>
#include <QGridLayout>
#include <QGroupBox>
#include <QLabel>
#include <QMainWindow>
#include <QPixmap>
#include <QResizeEvent>
#include <QTimer>
using namespace std;
class LabelImage: public QLabel {
private:
QPixmap _qPixmap, _qPixmapScaled;
public:
void setPixmap(const QPixmap &qPixmap) { setPixmap(qPixmap, size()); }
protected:
virtual void resizeEvent(QResizeEvent *pQEvent);
private:
void setPixmap(const QPixmap &qPixmap, const QSize &size);
};
void LabelImage::resizeEvent(QResizeEvent *pQEvent)
{
QLabel::resizeEvent(pQEvent);
setPixmap(_qPixmap, pQEvent->size());
}
void LabelImage::setPixmap(const QPixmap &qPixmap, const QSize &size)
{
_qPixmap = qPixmap;
_qPixmapScaled = _qPixmap.scaled(size, Qt::KeepAspectRatio);
QLabel::setPixmap(_qPixmapScaled);
}
int main(int argc, char **argv)
{
cout << QT_VERSION_STR << endl;
// main application
#undef qApp // undef macro qApp out of the way
QApplication qApp(argc, argv);
// setup GUI
QMainWindow qWin;
QGroupBox qBox;
QGridLayout qGrid;
// a macro for the keyboard lazy:
#define Q_LBL_WITH_POS(ROW, COL) \
QLabel qLbl##ROW##COL(QString::fromLatin1(#ROW", "#COL)); \
/*qLbl##ROW##COL.setFrameStyle(QLabel::Raised | QLabel::Box);*/ \
qGrid.addWidget(&qLbl##ROW##COL, ROW, COL, Qt::AlignCenter)
Q_LBL_WITH_POS(0, 0);
Q_LBL_WITH_POS(0, 1);
Q_LBL_WITH_POS(0, 2);
Q_LBL_WITH_POS(1, 0);
LabelImage qLblImg;
qLblImg.setFrameStyle(QLabel::Raised | QLabel::Box);
qLblImg.setAlignment(Qt::AlignCenter);
//qLblImg.setMinimumSize(QSize(1, 1)); // seems to be not necessary
qLblImg.setSizePolicy(
QSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored));
QPixmap qPM;
if (qPM.load("cats.jpg")) qLblImg.setPixmap(qPM);
else {
qLblImg.setText(
QString::fromLatin1("Sorry. Cannot find file 'cats.jpg'."));
}
qGrid.addWidget(&qLblImg, 1, 1, Qt::AlignCenter);
qGrid.setRowStretch(1, 1); // tell QGridLayout to stretch this cell...
qGrid.setColumnStretch(1, 1); // ...prior to other cells (w/ stretch 0)
Q_LBL_WITH_POS(1, 2);
Q_LBL_WITH_POS(2, 0);
Q_LBL_WITH_POS(2, 1);
Q_LBL_WITH_POS(2, 2);
qBox.setLayout(&qGrid);
qWin.setCentralWidget(&qBox);
qWin.show();
// run application
return qApp.exec();
}
注意:
图像的宽高比仍然正确,但调整大小不再起作用。因此,我添加了QGrid::setRowStretch()
和QGrid::setColumnStretch()
。不幸的是,这并没有太大变化。
我搜索了这个主题并找到了SO: Change resize behavior in Qt layouts。实际上,这也没有帮助,但让我怀疑QGridLayout
可能是这个布局问题的实际来源。
为了更好地显示此布局问题,我在所有窗口小部件中添加了框架。令我惊讶的是,它突然发挥作用。
我认为QGridLayout
中的布局在某种程度上不符合预期(尽管我不敢称之为bug)。但是,围绕图像制作框架的解决方法是我可以忍受的。 (实际上,它看起来并不那么糟糕。)
更新的代码示例的快照: