Qt - 如何创建随窗口缩放并保持纵横比的图像?

谢菲·加里

我正在尝试在 QT(内部标签)中创建图像,该图像会根据窗口大小的变化而改变大小,但也会保持纵横比。

最好的方法是什么?

舍夫

你用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()方法,并实际上存储了两个版本的像素图-原始版本和缩放版本。我不确定这是否有必要 - 这是我第一次使用QPixmap.

  2. 在阅读 Qt 文档时,我发现了QLabel::setScaledContents()我试了一下,但它没有考虑像素图的纵横比。我找不到将其设置为额外选项的方法。(可能是,我搜索得不够。我禁用了此代码,但保留它以记住这是“错误的方向”。)

  3. 在中间版本中,我能够放大应用程序(并且缩放很好),但我无法缩小它。谷歌搜索一下我发现SO:Enable QLabel to shrink even if it truncates text这解决了这个问题。

  4. 为了保持示例简短,我对图像文件名进行了硬编码。其实不用说应用程序的当前目录一定是文件所在的目录。(这在 Linux 中可能没有问题,但我必须适当调整 VS2013 中的调试设置。)

以下是我的测试应用程序的快照:

testQLabelImage.exe 的快照

这应该(当然)适用于可以加载到 Qt 中的任何图像文件。但是,为了使示例完整(并且因为 Internet 和猫的图片确实属于一起),我还提供了示例图像(供下载)。

猫.jpg

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

编辑:

根据Shefy Gurary的反馈,此操作无法在中正常运行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. The aspect ratio of image was still correct but the resizing didn't work anymore. Thus, I added QGrid::setRowStretch() and QGrid::setColumnStretch(). Unfortunately, this didn't change much.

  2. I googled this topic and found SO: Change resize behavior in Qt layouts. Actually, This didn't help really also but made me suspective that the QGridLayout could be the actual source of this layout issue.

  3. For better visualization of this layout issue, I added frames to all my widgets. To my surprise, it worked suddenly.

I assume that the layout in the QGridLayout works somehow not like expected (although I wouldn't dare to call it a bug). However, the workaround to make a frame around the image is something I could live with. (Actually, it looks not that bad.)

A snapshot of the updated code sample:

testQLabelImage.exe (V2.0) 快照

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章