Qt – 如何创build与窗口缩放的图像,并保持宽高比?

我试图在QT(内部标签)中创build图像,根据窗口大小的变化来改变大小,但也会保持宽高比。

什么是最好的办法呢?

你用linux标记了这个问题。 我在Windows 10上开发 – 离我最近的Linux是cygwin。 因此,我在VS2013中解决了它,但是,嘿,这是Qt的C ++。 它应该是便携式的…

实际上, QPixmap::scaled()已经内置了保持高宽比所需的所有内容。 因此,我的解决方案是相当短的QLabelQPixmap一起插入。

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

笔记:

  1. 我重载了QLabel::setPixmap()方法,实际上存储了两个版本的pixmap – 原始和缩放。 我不确定这是否有必要 – 这是我第一次使用QPixmap

  2. 在阅读Qt文档时,我发现QLabel :: setScaledContents() 。 我试了一下,但没有考虑像素图的长宽比。 我无法找到一个方法来设置这个额外的选项。 (可能是,我没有足够的搜索,我禁用了这个代码,但留下来记住这是“错误的方向”。)

  3. 在中间版本中,我能够扩大应用程序(并且缩放比较好),但我无法缩小它。 谷歌搜索一点,我发现SO:即使它截断文本,使QLabel缩小 。 这解决了这个问题。

  4. 为了保持简短的样本,我硬编码的图像文件名称。 实际上没必要说应用程序的当前目录必须是文件所在的目录。 (这在Linux中可能不是问题,但我必须适当调整VS2013中的调试设置。)

下面是我的测试应用程序的快照。

testQLabelImage.exe的快照

这应该工作(当然)与任何可以加载到Qt的图像文件。 但是,为了使样本完整(因为互联网和猫的图片真的属于一起),我也提供样本图像(下载)。

cats.jpg

左边是马克斯,右边是莫里茨。 (或相反亦然?)

编辑:

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

笔记:

  1. 图像的宽高比仍然正确,但调整大小不再工作。 因此,我添加了QGrid::setRowStretch()QGrid::setColumnStretch() 。 不幸的是,这并没有太大的改变。

  2. 我GOOGLE了这个话题,发现SO:改变在Qt布局调整行为 。 其实,这也没有帮助,但让我怀疑QGridLayout可能是这个布局问题的实际来源。

  3. 为了更好的可视化这个布局问题,我给所有的小部件添加了框架。 令我惊讶的是,它突然工作。

我假设QGridLayout中的布局在某种程度上不像预期的那样工作(尽管我不敢把它称为一个bug)。 但是,围绕图像制作框架的解决方法是我可以忍受的。 (其实看起来并不是那么糟糕。)

更新的代码示例的快照:

testQLabelImage.exe(V2.0)的快照