使用QChart绘制一个随着时间的变化而动态显示的折线图
每一秒增加1个点,总共显示10s内的数据
显然x轴我们使用日期时间轴
同时使用1个定时器,每隔1秒往折线系列中添加1个数据进去
步骤如下:
1、创建图表视图
//1、创建图表视图
QChartView* view=new QChartView(this);
2、创建图表,并将图表设置给视图
//2.创建图表
QChart * chart = new QChart();
//3.将图表设置给图表视图
view -> setChart(chart);
//设置标题
chart->setTitle("动态折线图");
chart->legend()->show();//显示或者隐藏图例(默认显示)
3、创建x轴(采用QDateTimeAxis日期时间轴),将x轴加到图表中,并设置x的范围为[当前时间,当前时间往后推10s]
//构建x轴-日期时间轴
QDateTimeAxis * axisX = new QDateTimeAxis(this);
axisX -> setTitleText("时间轴");
QDateTime min = QDateTime::currentDateTime(); //当前时间
QDateTime max = min.addSecs(10); //当前时间+10s
axisX -> setRange(min, max); //设置范围,[当前时间,当前时间+10s]
axisX -> setTickCount(11);
axisX -> setFormat("hh:mm:ss"); //设置刻度值的格式
axisX -> setLabelsAngle(45);
chart -> addAxis(axisX, Qt::AlignBottom);
4、创建y轴,将y轴加到图标中
//构建y轴-数值轴
QValueAxis * axisY = new QValueAxis(this);
axisY -> setRange(1000, 2000);
axisY -> setTickCount(11);
axisY -> setTitleText("Y轴");
chart -> addAxis(axisY, Qt::AlignLeft);
5、创建折线系列,并添加到图表中,此时先不往折线系列中添加数据
//构建折线系列
QLineSeries * line = new QLineSeries(this);
line -> setName("时间轴");
chart -> addSeries(line);
6、将x轴和y轴和折线系列进行关联
line -> attachAxis(axisX);
line -> attachAxis(axisY);
7、创建定时器,并开启定时器,在定时器超时信号的槽函数中:
- 往折线系列中添加数据
- 并且x值(即当前时间)超过了最开始设定的最大值时,更新x轴的范围,新的范围为[当前时间往前推10s,当前时间]
- 同时删除不可见的点,防止内存一直增长
//定时器中动态添加数据 QTimer * t = new QTimer(this); t -> setTimerType(Qt::PreciseTimer); connect(t, & QTimer::timeout, this, [ = ]() { auto x = QDateTime::currentMSecsSinceEpoch(); //获取当前时间的毫秒数 auto y = QRandomGenerator::global() -> bounded(1000, 2000); //y值采用随机数 //第一次触发这个槽函数时更新一下范围,解决开头有几个点没有的bug //因为前面设置x轴范围获取的时间和定时器超时的时间点有10ms的间隔,毕竟x轴的精度是毫秒级别 //这个更新只执行一次 static std::once_flag once; std::call_once(once, [ = ]() { QDateTime min_ = QDateTime::fromMSecsSinceEpoch(x); //当前时间 QDateTime max_ = min_.addSecs(10); //当前时间+10s axisX -> setRange(min_, max_); //设置范围,10s的范围 }); //添加数据 line -> append(x, y); QDateTime max = axisX -> max(); //当前x值超过了x轴的最大值 if (x > max.toMSecsSinceEpoch()) { QDateTime new_max = QDateTime::fromMSecsSinceEpoch(x); QDateTime new_min = max.addSecs(-10); //更新最大最小值,范围始终保持10s,更新x轴最大值为新的当前毫秒数 axisX -> setRange(new_min, new_max); //删除不可见的点,否则点数越来越多,内存耗尽 //每次删除第一个点 line -> removePoints(0, 1); } }); //开启定时器 t -> start(10); //10ms增加一个点
完整代码:
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include<QtCharts>
#include<QHBoxLayout>
#include<QPieSlice>
#include<QPieSeries>
#include<QBarSeries>
#include<QBarSet>
#include<QAreaSeries>
class Widget: public QWidget {
Q_OBJECT
public:
Widget(QWidget * parent = nullptr): QWidget(parent) {
resize(800, 600);
QHBoxLayout * h_box = new QHBoxLayout(this);
drawDynamicLineSeries();
}
~Widget() =default;
//绘制动态折线图
void drawDynamicLineSeries() {
//1、创建图表视图
QChartView * view = new QChartView(this);
this -> layout() -> addWidget(view);
//2.创建图表
QChart * chart = new QChart();
//3.将图表设置给图表视图
view -> setChart(chart);
//设置标题
chart -> setTitle("动态折线图");
chart -> legend() -> show(); //显示或者隐藏图例(默认显示)
//构建x轴-日期时间轴
QDateTimeAxis * axisX = new QDateTimeAxis(this);
axisX -> setTitleText("时间轴");
QDateTime min = QDateTime::currentDateTime(); //当前时间
QDateTime max = min.addSecs(10); //当前时间+10s
axisX -> setRange(min, max); //设置范围,[当前时间,当前时间+10s]
axisX -> setTickCount(11);
axisX -> setFormat("hh:mm:ss"); //设置刻度值的格式
axisX -> setLabelsAngle(45);
chart -> addAxis(axisX, Qt::AlignBottom);
//构建y轴-数值轴
QValueAxis * axisY = new QValueAxis(this);
axisY -> setRange(1000, 2000);
axisY -> setTickCount(11);
axisY -> setTitleText("Y轴");
chart -> addAxis(axisY, Qt::AlignLeft);
//构建折线系列
QLineSeries * line = new QLineSeries(this);
line -> setName("时间轴");
chart -> addSeries(line);
line -> attachAxis(axisX);
line -> attachAxis(axisY);
//定时器中动态添加数据
QTimer * t = new QTimer(this);
t -> setTimerType(Qt::PreciseTimer);
connect(t, & QTimer::timeout, this, [ = ]() {
auto x = QDateTime::currentMSecsSinceEpoch(); //获取当前时间的毫秒数
auto y = QRandomGenerator::global() -> bounded(1000, 2000); //y值采用随机数
//第一次触发这个槽函数时更新一下范围,解决开头有几个点没有的bug
//因为前面设置x轴范围获取的时间和定时器超时的时间点有10ms的间隔,毕竟x轴的精度是毫秒级别
//这个更新只执行一次
static std::once_flag once;
std::call_once(once, [ = ]() {
QDateTime min_ = QDateTime::fromMSecsSinceEpoch(x); //当前时间
QDateTime max_ = min_.addSecs(10); //当前时间+10s
axisX -> setRange(min_, max_); //设置范围,10s的范围
});
//添加数据
line -> append(x, y);
QDateTime max = axisX -> max();
//当前x值超过了x轴的最大值
if (x > max.toMSecsSinceEpoch()) {
QDateTime new_max = QDateTime::fromMSecsSinceEpoch(x);
QDateTime new_min = max.addSecs(-10);
//更新最大最小值,范围始终保持10s,更新x轴最大值为新的当前毫秒数
axisX -> setRange(new_min, new_max);
//删除不可见的点,否则点数越来越多,内存耗尽
//每次删除第一个点
line -> removePoints(0, 1);
}
});
//开启定时器
t -> start(10); //10ms增加一个点
}
};
#endif // WIDGET_H