【嵌入式Qt开发入门】如何使用Qt进行绘图——QPainter 绘图

13 篇文章 2 订阅

        绘图与图表在嵌入式里有的比较多,尤其是图表,我们常在股票里看到的“图表折线/曲线 图/饼状图等”都可以用 Qt 的图表来实现。绘图和图表的内容本章主要介绍绘图和图表的基本操作,以简单的例子呈现绘图与图表的用法,目的就是快速入门绘图与图表,关于绘图与图表详解最好是看 Qt 官方的帮助文档。

QPainter 绘图

        Qt 里的所有绘图,比如一个按钮和一个 Label 的显示,都有绘图系统来执行。绘图系统基于 QPainter、QPaintDevice 和 QPainEngine 类。QPainter 是可以直接用来操作绘图的类,而 QPaintDevice 和 QPainEngine 都比 QPainter 更底层,我们只需要了解一下 QPaintDevice 和 QPainEngine 就行了。可以用下面一张图来表示它们的关系。

        一般用于显示的类,如 QWidget、QPixmap、QImage、Qlabel 等可视类控件都可以充当绘 图区域的“画布”,从 QWidget 继承的类都有 virtual void paintEvent(QPaintEvent *event);属性。这个 paintEvent()是一个虚函数,它在 qwidget.h 头文件的 protected:修饰符下。

        paintEvent()事件可以被重写。(解释:什么是绘图事件?可以这么理解,当界面初始化或者需要刷新时才会执行的事件,也就是说绘图事件在构造对象实例化时会执行,需要刷新界面我们可以使用 update()方法执行 paintEvent()事件)。

        paintEvent()事件是父类 QWidget 提供给子类的接口,在父类里定义为空,所以可以说 paintEvent()事件就是专门给子类画图用的。

        paintEvent()事件在子类重写的基本结构如下:

void Widget::paintEvent(QPaintEvent *)
{
    /* 指定画图的对象,this 代表是本 Widget */
    QPainter painter(this);
    // 使用 painter 在对象上绘图...
}

应用实例

        本例目的:快速了解 paintEvent()事件的使用。

        项目名称:qpainter。本例使用一张 CD 图片,用 QPainter 在 paintEvent()将 CD 画在窗口的中心,并且每 100ms 旋转 1 度角度。所以 CD 看起来是旋转了的效果。

        头文件“mainwindow.h”具体代码如下。

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QPainter>
#include <QPaintEvent>
#include <QTimer>

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

    /* 重写父类下的protected方法*/
protected:
    void paintEvent(QPaintEvent *);

private:
    /* 定时器,用于定时更新界面 */
    QTimer *timer;
    /* 角度 */
    int angle;

private slots:
    /* 槽函数 */
    void timerTimeOut();

};
#endif // MAINWINDOW_H

        因为 paintEvent()是父类 QWidget 的 protected 修饰符下虚方法(虚函数),所以建议重写时也写到子类下的 protected 修饰符下。

        在源文件“mainwindow.cpp”具体代码如下。

#include "mainwindow.h"
#include "QDebug"
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    /* 设置主窗口位置及颜色 */
    this->setGeometry(0, 0, 800, 480);
    setPalette(QPalette(Qt::gray));
    setAutoFillBackground(true);

    /* 定时器实例化 */
    timer = new QTimer(this);

    /* 默认角度为0 */
    angle = 0;

    /* 定时100ms */
    timer->start(100);

    /* 信号槽连接 */
    connect(timer, SIGNAL(timeout()), this, SLOT(timerTimeOut()));
}

MainWindow::~MainWindow()
{
}

void MainWindow::timerTimeOut()
{
    /* 需要更新界面,不设置不更新 */
    this->update();
}

void MainWindow::paintEvent(QPaintEvent *)
{
    /* 指定父对象,this指本窗口 */
    QPainter painter(this);

    /* 设置抗锯齿,流畅转换 */
    painter.setRenderHints(QPainter::Antialiasing
                           | QPainter::SmoothPixmapTransform);
    /* 计算旋转角度 */
    if (angle++ == 360)
        angle = 0;

    /* QPixmap类型对象 */
    QPixmap image;

    /* 加载 */
    image.load(":/image/cd.png");

    /* QRectF即,继承QRect(Qt的矩形类),F代表精确到浮点类型 */
    QRectF rect((this->width() - image.width()) / 2,
                (this->height() - image.height()) / 2,
                image.width(),
                image.height());

    /* 默认参考点为左上角原点(0,0),因为旋转需要以图形的中心为参考点,
     * 我们使用translate把参考点设置为CD图形的中心点坐标 */
    painter.translate(0 + rect.x() + rect.width() / 2,
                      0 + rect.y() + rect.height() / 2);

    /* 旋转角度 */
    painter.rotate(angle);

    /* 现在参考点为CD图形的中心,我们需要把它设置回原点的位置,
     * 所以需要减去上面加上的数 */
    painter.translate(0 - (rect.x() + rect.width() / 2),
                      0 - (rect.y() + rect.height() / 2));

    /* 画图,QPainter提供了许多drawX的方法 */
    painter.drawImage(rect, image.toImage(), image.rect());

    /* 再画一个矩形 */
    painter.drawRect(rect.toRect());
}

        首先实现paintEvent()。先指定需要画图的对象,加图片后,使用 translate() 设置参考原点,旋转一定的角度后再恢复参考原点。之后就开始画图。在参考原点处可能比较难理解,大家根据上面的注释多多分析。

        然后,定时100ms 更新一次界面。因为 paintEvent事件在构造函数执行时只会执行一次。 我们需要使用 update()方法来更新界面,才能看到 CD 旋转的效果。

程序运行效果

        编译运行程序后可以看到如下效果,CD 的外框加画了一个矩形,使旋转更明显。使用 paintEvent 可以实现一些需要绘图的情景,它可能比 Qt 动画类更容易实现。结合 Qt 的画笔, 也可以设计一个绘图软件,这多得益于 paintEvent()与 QPainter 使界面开发多了一些可能。在界面设计里,重绘界面使用 paintEvent()也比较多,需要我们掌握这部分内容。

 

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值