每次给这类文章取名字都很烦,一不小心就又臭又长了!>.< ...... 下面转入正(cai)题(guai) 相信大家一开始也和我一样,用QLabel来充当图像的显示控件,不过应该很快就会发现QLabel显示出来图像后,如果再改变父级控件的大小,此时QLabel的图像不会跟着变大而是保持原来的大小。更为糟糕的是,父级控件无法缩小了,因为QLabel的图像不会自动缩小,限制了父级控件的minimumSize! 其实是一个很囧的问题,网上一搜会发现几年前就有人提出怎么没有一个专门的QImageLabel啊?可能priority太低吧……Anyway,下面介绍通过自定义类(继承QWidget)实现一个可以自动缩放图像的控件。
这么高(diao)端(bao)的办法显然不是我原创的,主要借鉴自Stackoverflow的一个答案。
先贴出我的qimageviewer.h源码:
#ifndef QIMAGEVIEWER_H #define QIMAGEVIEWER_H #include <QWidget> #include <QPainter> #include <QPaintEvent> class QImageViewer : public QWidget { Q_OBJECT public: explicit QImageViewer(QWidget *parent = 0); const QPixmap *pixmap() const; public slots: void setPixmap(const QPixmap &pix); protected: void paintEvent(QPaintEvent *); private: QPixmap m_pixmap; }; #endif // QIMAGEVIEWER_H
再来就是qimageviewer.cpp了:
#include "qimageviewer.h" QImageViewer::QImageViewer(QWidget *parent) : QWidget(parent) { } void QImageViewer::paintEvent(QPaintEvent *event) { QWidget::paintEvent(event); if (m_pixmap.isNull()) return; QPainter painter(this); painter.setRenderHint(QPainter::SmoothPixmapTransform); QSize pixSize = m_pixmap.size(); pixSize.scale(event->rect().size(), Qt::KeepAspectRatio); QPoint topleft; topleft.setX((this->width() - pixSize.width()) / 2); topleft.setY((this->height() - pixSize.height()) / 2); painter.drawPixmap(topleft, m_pixmap.scaled(pixSize, Qt::KeepAspectRatio, Qt::SmoothTransformation)); } const QPixmap* QImageViewer::pixmap() const { return &m_pixmap; } void QImageViewer::setPixmap(const QPixmap &pix) { m_pixmap = pix; this->update(); }
我在Stackoverflow的答案上做了点小改进,一是图像居中显示,二是设置图像(setPixmap)后立即刷新界面(update)。
使用这个类很简单呢,Qt Designer下拖一个Widget,然后Promote to QImageViewer(第一次添加需要手动输入类和类的源码名字)就可以了。当然,用代码写界面就更easy了。
设置图像调用setPixmap函数就okay了。这个控件比QLabel给力多了吧,专职显示图像,而且随着父级控件(窗体)的变化自动改变尺寸。
2014-03-13补充:
因为是自定义的QWidget派生类,需要对paintEvent添加一些代码,才能使得在Qt Designer里通过StyleSheet更改背景颜色(background-color)生效。需要添加的代码如下:
QStyleOption opt; opt.init(this); QPainter p(this); style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
接合本例使用,切记在写在if (m_pixmap.isNull()) return;之前,否则没有图像显示的时侯还是不会渲染背景颜色。
参考来源:
Stackoverflow