绘图与图表
QPainter 绘图
概述
-
绘图系统核心类
-
QPainter: 主要用于直接操作绘图的类
-
QPaintDevice: 比 QPainter 更底层,定义了一个可以绘图的设备
-
QPainEngine: 比 QPainter 更底层,用于实现绘图设备的具体绘图过程
-
-
可作为绘图“画布”的类
-
QWidget: 所有可视类控件的基类,提供了绘图区域
-
QPixmap: 用于离屏绘图的设备
-
QImage: 提供了对图像数据的操作和存储
-
QLabel: 用于显示文本或图像的控件
-
-
paintEvent() 事件
-
定义: 这是一个虚函数,在 qwidget.h 头文件中使用 protected 修饰符声明
-
作用: 当界面初始化或需要刷新时,触发绘图事件
-
重写: 子类继承自 QWidget,可以重写这个事件来执行自定义的绘图操作
-
-
触发 paintEvent() 事件
-
初始化: 界面初始化时自动触发
-
刷新: 需要刷新界面时,通过调用 update() 方法来触发
-
-
重写 paintEvent() 的基本结构
-
void Widget::paintEvent(QPaintEvent )
{
/ 指定画图的对象,this 代表是本 Widget */
QPainter painter(this);
// 使用 painter 在对象上绘图…
} -
QPainter: 创建一个 QPainter 对象,指定绘图目标为当前 Widget (this)
-
绘图操作: 使用 QPainter 对象进行各种绘图操作(如绘制图形、文本、图像等)
-
应用实例
-
使用一张CD 图片,用 QPainter 在 paintEvent()将 CD 画在窗口的中心,并且每 100ms 旋转 1 度角度
-
mainwindow.h
-
1 #ifndef MAINWINDOW_H
2 #define MAINWINDOW_H
3
4 #include
5 #include
6 #include
7 #include
8
9 class MainWindow : public QMainWindow
10 {
11 Q_OBJECT
12
13 public:
14 MainWindow(QWidget parent = nullptr);
15 ~MainWindow();
16
17 / 重写父类下的 protected 方法*/
18 protected:
19 void paintEvent(QPaintEvent );
20
21 private:
22 / 定时器,用于定时更新界面 */
23 QTimer timer;
24 / 角度 /
25 int angle;
26
27 private slots:
28 / 槽函数 */
29 void timerTimeOut();
30
31 };
32 #endif // MAINWINDOW_H -
第 18 行,因为 paintEvent()是父类 QWidget 的 protected 修饰符下虚方法(虚函数),所以建议重写时也写到子类下的 protected 修饰符下
-
-
mainwindow.cpp
-
1 #include “mainwindow.h”
2 #include “QDebug”
3 MainWindow::MainWindow(QWidget parent)
4 : QMainWindow(parent)
5{
6 / 设置主窗口位置及颜色 /
7 this->setGeometry(0, 0, 800, 480);
8 setPalette(QPalette(Qt::gray));
9 setAutoFillBackground(true);
10
11 / 定时器实例化 /
12 timer = new QTimer(this);
13
14 / 默认角度为 0 /
15 angle = 0;
16
17 / 定时 100ms /
18 timer->start(100);
19
20 / 信号槽连接 /
21 connect(timer, SIGNAL(timeout()), this, SLOT(timerTimeOut()));
22 }
23
24 MainWindow::~MainWindow()
25 {
26 }
27
28 void MainWindow::timerTimeOut()
29 {
30 / 需要更新界面,不设置不更新 */
31 this->update();
32 }
33
34 void MainWindow::paintEvent(QPaintEvent )
35 {
36 / 指定父对象,this 指本窗口 /
37 QPainter painter(this);
38
39 / 设置抗锯齿,流畅转换 /
40 painter.setRenderHints(QPainter::Antialiasing
41 | QPainter::SmoothPixmapTransform);
42 / 计算旋转角度 /
43 if (angle++ == 360)
44 angle = 0;
45
46 / QPixmap 类型对象 /
47 QPixmap image;
48
49 / 加载 /
50 image.load(“:/image/cd.png”);
51
52 / QRectF 即,继承 QRect(Qt 的矩形类),F 代表精确到浮点类型 /
53 QRectF rect((this->width() - image.width()) / 2,
54 (this->height() - image.height()) / 2,
55 image.width(),
56 image.height());
57
58 / 默认参考点为左上角原点(0,0),因为旋转需要以图形的中心为参考点,
59 * 我们使用 translate 把参考点设置为 CD 图形的中心点坐标 /
60 painter.translate(0 + rect.x() + rect.width() / 2,
61 0 + rect.y() + rect.height() / 2);
62
63 / 旋转角度 /
64 painter.rotate(angle);
65
66 / 现在参考点为 CD 图形的中心,我们需要把它设置回原点的位置,
67 * 所以需要减去上面加上的数 /
68 painter.translate(0 - (rect.x() + rect.width() / 2),
69 0 - (rect.y() + rect.height() / 2));
70
71 / 画图,QPainter 提供了许多 drawX 的方法 /
72 painter.drawImage(rect, image.toImage(), image.rect());
73
74 / 再画一个矩形 */
75 painter.drawRect(rect.toRect());
76 } -
第 34~76 行,paintEvent()的实现
-
首先先指定需要画图的对象,加图片后,使用 translate()
设置参考原点,旋转一定的角度后再恢复参考原点 -
之后就开始画图
-
-
第 31 行,定时 100ms 更新一次界面
-
因为 paintEvent 事件在构造函数执行时只会执行一次
-
我们需要使用 update()方法来更新界面,才能看到 CD 旋转的效果
-
-
程序运行效果
- CD 的外框加画了一个矩形,使旋转更明显
QChart 图表
概述
-
功能概述
-
Qt Charts: 提供了方便的接口来绘制常见的图表,如曲线图、折线图、柱状图和饼状图等
-
优点: 不需要额外学习第三方组件或开发自定义组件,Qt 的帮助文档已经详细说明了 Qt Charts 的使用方法
-
-
文档参考
- 查看 Qt 文档: 需要使用时,可以查阅官方文档获取详细的使用方法和示例
-
继承关系
-
理解继承关系: 通过查看类的继承关系,可以了解类的来源和结构,它们是逐步构建起来的
-
快捷键: 在 Qt Creator 中使用快捷键 Ctrl + Shift + T,可以查看指定类的继承关系
-
-
项目设置
-
添加模块: 在项目的 .pro 文件中添加以下语句,以使用 Qt Charts 模块
-
QT += charts
-
-
包含头文件和命名空间
-
包含头文件: 在使用 Qt Charts 类时,除了包含相应的头文件外,还需要使用特定的命名空间
-
命名空间使用方法
-
在头文件中加上以下宏定义
- QT_CHARTS_USE_NAMESPACE
-
或者在头文件类外使用 using 语句
- using namespace QtCharts;
-
-
应用实例
-
基本流程
-
创建必要对象
-
QSplineSeries: 表示曲线对象
-
QChart: 表示图表对象
-
QChartView: 表示图表视图对象
-
-
创建坐标轴
- 创建 QValueAxis 的 X 轴和 Y 轴对象
-
配置图表
-
将坐标轴添加到图表上
-
将曲线对象添加到图表,并关联坐标轴
-
-
配置视图
- 将图表添加到图表视图中
-
数据更新
- 由系统生成随机数据,并定期更新曲线上的数据
-
-
代码
-
将项目文件第一行添加的代码如下
- 1 QT += core gui charts
-
mainwindow.h
- 1 #ifndef MAINWINDOW_H
2 #define MAINWINDOW_H
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9 #include
10
11 /* 必需添加命名空间 */
12 QT_CHARTS_USE_NAMESPACE
13
14 class MainWindow : public QMainWindow
15 {
16 Q_OBJECT
17
18 public:
19 MainWindow(QWidget parent = nullptr);
20 ~MainWindow();
21
22 private:
23 / 接收数据接口 /
24 void receivedData(int);
25
26 / 数据最大个数 /
27 int maxSize;
28
29 / x 轴上的最大值 /
30 int maxX;
31
32 / y 轴上的最大值 /
33 int maxY;
34
35 / y 轴 */
36 QValueAxis axisY;
37
38 / x 轴 /
39 QValueAxis axisX;
40
41 / QList int 类型容器 /
42 QList data;
43
44 / QSplineSeries 对象(曲线)/
45 QSplineSeries splineSeries;
46
47 / QChart 图表 */
48 QChart chart;
49
50 / 图表视图 */
51 QChartView chartView;
52
53 / 定时器 */
54 QTimer *timer;
55
56 private slots:
57 void timerTimeOut();
58 };
59 #endif // MAINWINDOW_H
- 1 #ifndef MAINWINDOW_H
-
mainwindow.cpp
-
1 #include “mainwindow.h”
2 #include
3 MainWindow::MainWindow(QWidget parent)
4 : QMainWindow(parent)
5{
6 / 设置最显示位置与大小 /
7 this->setGeometry(0, 0, 800, 480);
8 / 最大储存 maxSize - 1 个数据 /
9 maxSize = 51;
10 / x 轴上的最大值 /
11 maxX = 5000;
12 / y 轴最大值 /
13 maxY = 40;
14
15 / splineSeries 曲线实例化(折线用 QLineSeries) /
16 splineSeries = new QSplineSeries();
17 / 图表实例化 /
18 chart = new QChart();
19 / 图表视图实例化 /
20 chartView = new QChartView();
21
22 / 坐标轴 /
23 axisY = new QValueAxis();
24 axisX = new QValueAxis();
25 / 定时器 /
26 timer = new QTimer(this);
27
28 / legend 译图例类型,以绘图的颜色区分,本例设置为隐藏 /
29 chart->legend()->hide();
30 / chart 设置标题 /
31 chart->setTitle(“实时动态曲线示例”);
32 / 添加一条曲线 splineSeries /
33 chart->addSeries(splineSeries);
34
35 / 设置显示格式 /
36 axisY->setLabelFormat(“%i”);
37 / y 轴标题 /
38 axisY->setTitleText(“温度/℃”);
39 / y 轴标题位置(设置坐标轴的方向) /
40 chart->addAxis(axisY, Qt::AlignLeft);
41 / 设置 y 轴范围 /
42 axisY->setRange(0, maxY);
43 / 将 splineSeries 附加于 y 轴上 /
44 splineSeries->attachAxis(axisY);
45
46 / 设置显示格式 /
47 axisX->setLabelFormat(“%i”);
48 / x 轴标题 /
49 axisX->setTitleText(“时间/ms”);
50 / x 轴标题位置(设置坐标轴的方向) /
51 chart->addAxis(axisX, Qt::AlignBottom);
52 / 设置 x 轴范围 /
53 axisX->setRange(0, maxX);
54 / 将 splineSeries 附加于 x 轴上 /
55 splineSeries->attachAxis(axisX);
56
57 / 将图表的内容设置在图表视图上 /
58 chartView->setChart(chart);
59 / 设置抗锯齿 /
60 chartView->setRenderHint(QPainter::Antialiasing);
61
62 / 设置为图表视图为中心部件 /
63 setCentralWidget(chartView);
64
65 / 定时 200ms /
66 timer->start(200);
67 / 信号槽连接 /
68 connect(timer, SIGNAL(timeout()), this, SLOT(timerTimeOut()));
69
70 / 设置随机种子,随机数初始化 /
71 qsrand(time(NULL));
72 }
73
74 MainWindow::~MainWindow()
75 {
76 }
77
78 void MainWindow::timerTimeOut()
79 {
80 / 产生随机 0~maxY 之间的数据 /
81 receivedData(qrand() % maxY );
82 }
83
84 void MainWindow::receivedData(int value)
85 {
86 / 将数据添加到 data 中 /
87 data.append(value);
88
89 / 当储存数据的个数大于最大值时,把第一个数据删除 /
90 while (data.size() > maxSize) {
91 / 移除 data 中第一个数据 /
92 data.removeFirst();
93 }
94
95 / 先清空 /
96 splineSeries->clear();
97
98 / 计算 x 轴上的点与点之间显示的间距 /
99 int xSpace = maxX / (maxSize - 1);
100
101 / 添加点,xSpace * i 表示第 i 个点的 x 轴的位置 */
102 for (int i = 0; i < data.size(); ++i) {
103 splineSeries->append(xSpace * i, data.at(i));
104 }
105 } -
第 84~105 行,是实现曲线移动的重要代码
-
算法逻辑
-
当数据点个数超过最大值时,删除第一个数据点
-
通过反复删除和添加数据点,控制数据点数量
-
-
数据移动实现
- 旧数据点的删除和新数据点的添加,使曲线在图表视图中动态更新,实现数据移动的视觉效果
-
-
-