曲线图绘制

qt的曲线绘制有三种类,分别是Qcustomplot、QChart、Qwt。

比较

  • 美观方面:

    • Qcustomplot≈Qchart > Qwt
    • Qcustomplot界面简洁大方;
    • Qchart界面华丽优美,在数据量大的时候会引响鼠标的缩放、移动图表操作;
    • Qwt界面老旧,在美观上不如Qcustomplot和Qchart ,并且在使用鼠标移动图表时会产生空白区域。
  • 性能方面:

    • 绘制数据性能:Qchart>Qcustomplot > Qwt

    • 绘制数据数量:Qcustomplot >Qchart> Qwt

    • 绘制1000个数据点时,qcustomplot平均耗时 13.6毫秒,Qwt平均耗时40毫秒,QChart平均耗时12.5毫秒;

      绘制10000个数据点时,qcustomplot平均耗时 21.6毫秒,Qwt平均耗时78毫秒,QChart平均耗时13.5毫秒;

      绘制100000个数据点时,qcustomplot平均耗时22.5毫秒,Qwt平均耗时524毫秒,QChart平均耗时20.7毫秒;

      绘制500000个数据点时,qcustomplot平均耗时43.3毫秒,QChart平均耗时194.25毫秒。

  • 功能方面:

    • QChart、Qwt功能比较齐全,并且可绘制图表种类多;
    • qcustomplot在图表种类上、常用功能上较少。
  • 使用方面:

    • QChart无需配置,主要在安装Qt时勾选就可以,在程序编写时上手较慢,许多功能需要重写;
    • Qwt安装配置比较复杂;
    • QCustomPlot体积小、简单易用,上手快,并且QCustomPlot只有两个源文件,可直接添加进工程,更容易直接修改源码。

Qwt 下载地址

Qcustomplot下载地址

QChart不用下载,只需在安装qt时候进行选择组件。

在这里我使用的是QChart来进行设计的毕设,首先是对.pro文件进行追加代码charts

1
2
QT      += core gui
QT += charts

进行编写mainwindow.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QChartView>
#include <QLineSeries>
#include <QChart>
#include <QValueAxis>
#include <QMouseEvent>
#include <QGraphicsSimpleTextItem>
#include <QSplineSeries>
#include <QDebug>
#include <QTimer>
#include <math.h>

QT_CHARTS_USE_NAMESPACE

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
Q_OBJECT

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

protected: //实现对于图线的缩放平移,定义的鼠标事件
void mouseDoubleClickEvent(QMouseEvent *event);
void mousePressEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
void wheelEvent(QWheelEvent *event);
private:
Ui::MainWindow *ui;

QPoint m_pointUsed; //保存旧坐标
bool m_isPress; //是否按下鼠标

double m_dMinX, m_dMaxX, m_dMinY, m_dMaxY; //保存图表轴初始大小
void receivedData(int);
int maxSize;
int maxX;
int maxY;
QValueAxis *axisY;
QValueAxis *axisX;
QList<int>data;
QSplineSeries *splineSeries; //曲线
QChart *chart;
QChartView *chartView;
QTimer *timer;
};
#endif // MAINWINDOW_H

mainwindow.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QRandomGenerator>
#include <QWidget>
#include <QDebug>
#include <math.h>
#include <QToolTip>

MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);

/* 设置最显示位置与大小 */
this->setGeometry(0, 0, 800, 480);
/* 最大储存 maxSize - 1 个数据 */
maxSize = 1000-1;
/* x 轴上的最大值 */
maxX = 2000;
/* y 轴最大值 */
maxY = 64000;
/* splineSeries 曲线实例化(折线用 QLineSeries) */
splineSeries = new QSplineSeries();
splineSeries->setName("第一条线");

/* 图表实例化 */
chart = new QChart();
/* 图表视图实例化 */
chartView = new QChartView();

/* 坐标轴 */
axisY = new QValueAxis();
axisX = new QValueAxis();
/* 定时器 */
timer = new QTimer(this);

/* legend 译图例类型,以绘图的颜色区分, 本例设置为隐藏 */
chart->legend()->hide();
/* chart 设置标题 */
chart->setTitle("拉曼光谱");
/* 添加一条曲线 splineSeries */
chart->addSeries(splineSeries);

/* 设置显示格式 */
axisY->setLabelFormat("%i");
/* y 轴标题 */
axisY->setTitleText("强度");
/* y 轴标题位置(设置坐标轴的方向) */
chart->addAxis(axisY, Qt::AlignLeft);
/* 设置 y 轴范围 */
axisY->setRange(0, maxY);
/* 将 splineSeries 附加于 y 轴上 */
splineSeries->attachAxis(axisY);
/* 设置显示格式 */
axisX->setLabelFormat("%i");
/* x 轴标题 */
axisX->setTitleText("拉曼位移(cm-1)");
/* x 轴标题位置(设置坐标轴的方向) */
chart->addAxis(axisX, Qt::AlignBottom);
/* 设置 x 轴范围 */
axisX->setRange(-28000, maxX);
/* 将 splineSeries 附加于 x 轴上 */
splineSeries->attachAxis(axisX);
/* 将图表的内容设置在图表视图上 */
chartView->setChart(chart);
/* 设置抗锯齿 */
chartView->setRenderHint(QPainter::Antialiasing);
/* 设置为图表视图为中心部件 */
setCentralWidget(chartView);

//使用定时器更新数据
timer = new QTimer(this); //初始化定时器
connect(timer, &QTimer::timeout,
[&]()
{
QVector<QPointF> point(maxSize + 1);
for(int i = 0; i < maxSize + 1; i++)
{
point[i].setX(i);
point[i].setY((int)QRandomGenerator::global()->bounded(1,1000));
}
splineSeries->replace(point); //更新数据
});
timer->start(20);

}

MainWindow::~MainWindow()
{
delete ui;
}

//鼠标按下
void MainWindow::mousePressEvent(QMouseEvent *event)
{

if (event->button() == Qt::LeftButton) //鼠标左键按下
{
m_pointUsed = event->pos(); //保存当前坐标
m_isPress = true;
}
else if(event->button() == Qt::MidButton) //鼠标中键按下
{
QLineSeries* l_series = (QLineSeries*)this->chart->series().at(0); //获取序列中的值
QVector<QPointF> l_vpointF = l_series->pointsVector();
QPointF l_curVal = this->chart->mapToValue(event->pos()); //返回鼠标处的值
QPointF l_pointF = l_vpointF.at(qRound(l_curVal.x())); //获取离鼠标的横坐标最近的点

QString l_strPos = QString("x:%0 y:%1").arg(l_pointF.x()).arg(l_pointF.y());
QString l_stStyle = "<p style=\"background:#00FFFF; border-radius: 1px 5px;font:12pt '宋体'\">%1</p>";
QToolTip::showText(cursor().pos(), l_stStyle.arg(l_strPos), this, QRect(0,0,1,1), 10000); //在点击位置显示提示信息
}
}

//鼠标双击
void MainWindow::mouseDoubleClickEvent(QMouseEvent *event)
{
if (event->button() == Qt::RightButton) //鼠标右键双击恢复最初大小
{
this->chart->axes(Qt::Horizontal).at(0)->setRange(m_dMinX, m_dMaxX);
this->chart->axes(Qt::Vertical).at(0)->setRange(m_dMinY, m_dMaxY);
}
}

//鼠标移动
void MainWindow::mouseMoveEvent(QMouseEvent *event)
{
if(m_isPress)
{
QPoint l_pointDiff = event->pos() - m_pointUsed; //当前坐标与按下鼠标处的坐标差
this->chart->scroll(-l_pointDiff.x(), l_pointDiff.y()); //移动图表
}
m_pointUsed = event->pos(); //保存当前坐标
}

//鼠标释放
void MainWindow::mouseReleaseEvent(QMouseEvent *event)
{
m_isPress = false;
}

//鼠标滚轮缩放
void MainWindow::wheelEvent(QWheelEvent *event)
{
QPointF l_curVal = this->chart->mapToValue(event->pos()); //返回鼠标处的值

QValueAxis *l_axisX = (QValueAxis*)this->chart->axes(Qt::Horizontal).at(0);
double l_fMinX = l_axisX->min();
double l_fMaxX = l_axisX->max();
QValueAxis *l_axisY = (QValueAxis*)this->chart->axes(Qt::Vertical).at(0);
double l_fMinY = l_axisY->min();
double l_fMaxY = l_axisY->max();

double l_fZoomMinX,l_fZoomMaxX,l_fZoomMinY,l_fZoomMaxY;
if(event->delta() > 0) //获取放大值
{
l_fZoomMinX = l_curVal.x() - (l_curVal.x() - l_fMinX) / 1.5;
l_fZoomMaxX = l_curVal.x() + (l_fMaxX - l_curVal.x()) / 1.5;
l_fZoomMinY = l_curVal.y() - (l_curVal.y() - l_fMinY) / 1.5;
l_fZoomMaxY = l_curVal.y() + (l_fMaxY - l_curVal.y()) / 1.5;
}
else //获取缩小值
{
l_fZoomMinX = l_curVal.x() - (l_curVal.x() - l_fMinX) * 1.5;
l_fZoomMaxX = l_curVal.x() + (l_fMaxX - l_curVal.x()) * 1.5;
l_fZoomMinY = l_curVal.y() - (l_curVal.y() - l_fMinY) * 1.5;
l_fZoomMaxY = l_curVal.y() + (l_fMaxY - l_curVal.y()) * 1.5;
}
this->chart->axes(Qt::Vertical).at(0)->setRange(l_fZoomMinY, l_fZoomMaxY); //设置轴范围
this->chart->axes(Qt::Horizontal).at(0)->setRange(l_fZoomMinX, l_fZoomMaxX);
}