自定义QWidget类使Qt图像控件能自动缩放

每次给这类文章取名字都很烦,一不小心就又臭又长了!>.< ...... 下面转入正(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

How to Change the Background Color of QWidget