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

标签 qt scale

我正在尝试在 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 中的调试设置。)

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

Snapshot of testQLabelImage.exe

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

cats.jpg

左边是Max,右边是Moritz。 (反之亦然?)

编辑:

根据 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. 我搜索了这个主题并找到了 SO: Change resize behavior in Qt layouts .实际上,这也没有帮助,但让我怀疑 QGridLayout 可能是这个布局问题的真正根源。

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

我假设 QGridLayout 中的布局以某种方式不符合预期(尽管我不敢将其称为错误)。但是,围绕图像制作框架的解决方法是我可以接受的。 (实际上,它看起来并没有那么糟糕。)

更新代码示例的快照:

Snapshot of testQLabelImage.exe (V2.0)

关于Qt - 如何创建随窗口缩放并保持纵横比的图像?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42833511/

相关文章:

java - libgdx 用户关闭屏幕

c++ - 如何在子部件而不是父部件上画一条线?

c++ - 如何在 catch 语句之外使用异常

Qt,非模态对话框不会自行关闭

c++ - 从类的 QList 访问 protected 成员,例如 QList<Account*>

Android:位图缩小质量低

python - 在 PySide QtGui.QStandardItem 中重写 text()

r - 使用 ggplot 绘制具有两个 y 刻度的图形

html - 我如何使用 MediaWiki 将图像的宽度缩放到窗口的百分比?

java - 如何启动 draw9patch 是否绝对有必要重新缩放图片?