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

时间:2017-03-16 12:00:38

标签: linux qt scale

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

最好的方法是什么?

1 个答案:

答案 0 :(得分:2)

您使用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中的调试设置。)

  5. 以下是我的测试应用的快照:

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

    3. 为了更好地显示此布局问题,我在所有窗口小部件中添加了框架。令我惊讶的是,它突然发挥作用。

    4. 我认为QGridLayout中的布局在某种程度上不符合预期(尽管我不敢称之为bug)。但是,围绕图像制作框架的解决方法是我可以忍受的。 (实际上,它看起来并不那么糟糕。)

      更新的代码示例的快照:

      Snapshot of testQLabelImage.exe (V2.0)