一、介绍qt的qchart是一个用于绘制图表和可视化数据的类。提供了一个灵活的、可扩展的、跨平台的图表绘制解决方案,可以用于各种应用程序,如数据分析、科学计算、金融交易等。
qchart支持多种类型的图表,包括折线图、散点图、柱状图、饼图等。它还支持多个数据系列(datasets)在同一个图表中显示,并且可以自定义各种图表属性和样式,如坐标轴标签、标题、图例等。
qchart还支持多种数据源(data sources),可以来自qt的数据模型(data models)、csv文件、json文件等。数据源可以是任何支持迭代器(iterator)的类型,因此可以轻松地与其他qt组件集成。
使用qchart可以轻松地创建交互式图表,如鼠标悬停提示(hover tooltip)、数据选择(data selection)等。此外,qchart还支持多种主题(themes)和自定义css样式,使得图表外观可以灵活地定制。
二、实现代码(1)qmainwindow以下是使用qt(c++)的qchart模块显示3个设备的动态温度曲线的代码实现:
【1】实现温度动态更新mainwindow.h
#ifndef mainwindow_h #define mainwindow_h #include #include #include #include qt_charts_use_namespace namespace ui { class mainwindow; } class mainwindow : public qmainwindow { q_object public: explicit mainwindow(qwidget *parent = nullptr); ~mainwindow(); private slots: void updatechartdata(); // 更新数据槽函数 private: ui::mainwindow *ui; qtimer *m_timer; // 定时器 qchart *m_chart; // 图表指针 qlineseries *m_series1; // 设备1温度曲线 qlineseries *m_series2; // 设备2温度曲线 qlineseries *m_series3; // 设备3温度曲线 int m_timecount; // 时间计数 }; #endif // mainwindow_hmainwindow.cpp
#include mainwindow.h #include ui_mainwindow.h mainwindow::mainwindow(qwidget *parent) : qmainwindow(parent), ui(new ui::mainwindow), m_timer(new qtimer(this)), m_chart(new qchart()), m_series1(new qlineseries()), m_series2(new qlineseries()), m_series3(new qlineseries()), m_timecount(0) { ui- >setupui(this); // 设置图表标题 m_chart- >settitle(temperature data); // 创建温度曲线图1并设置属性 m_series1- >setname(tr(device 1)); m_series1- >setcolor(qt::red); m_series1- >setpen(qpen(qt::red, 2)); m_chart- >addseries(m_series1); // 创建温度曲线图2并设置属性 m_series2- >setname(tr(device 2)); m_series2- >setcolor(qt::green); m_series2- >setpen(qpen(qt::green, 2)); m_chart- >addseries(m_series2); // 创建温度曲线图3并设置属性 m_series3- >setname(tr(device 3)); m_series3- >setcolor(qt::blue); m_series3- >setpen(qpen(qt::blue, 2)); m_chart- >addseries(m_series3); // 设置横轴属性 qvalueaxis *axisx = new qvalueaxis; axisx- >setrange(0, 30); axisx- >settitletext(time (s)); m_chart- >addaxis(axisx, qt::alignbottom); m_series1- >attachaxis(axisx); m_series2- >attachaxis(axisx); m_series3- >attachaxis(axisx); // 设置纵轴属性 qvalueaxis *axisy = new qvalueaxis; axisy- >setrange(0, 60); axisy- >settitletext(temperature (℃)); m_chart- >addaxis(axisy, qt::alignleft); m_series1- >attachaxis(axisy); m_series2- >attachaxis(axisy); m_series3- >attachaxis(axisy); // 定时更新数据 connect(m_timer, &qtimer::timeout, this, &mainwindow::updatechartdata); m_timer- >start(1000); // 每隔1秒钟更新一次数据 // 将图表添加到chartview中 ui- >chartview- >setchart(m_chart); ui- >chartview- >setrenderhint(qpainter::antialiasing); } mainwindow::~mainwindow() { delete ui; } void mainwindow::updatechartdata() { // 更新时间计数 m_timecount++; // 在温度曲线上增加一个点,模拟温度数据变化 qpointf p1(m_timecount, qrand() % 10 + 20); qpointf p2(m_timecount, qrand() % 10 + 30); qpointf p3(m_timecount, qrand() % 10 + 40); m_series1- >append(p1); m_series2- >append(p2); m_series3- >append(p3); // 清除多余的点,只保留最新的30个数据点 if (m_series1- >count() > 30) { m_series1- >removepoints(0, 1); } if (m_series2- >count() > 30) { m_series2- >removepoints(0, 1); } if (m_series3- >count() > 30) { m_series3- >removepoints(0, 1); } }在此代码中,定义了一个qtimer定时器对象,用于每隔一段时间更新温度曲线数据。在定时器的timeout信号触发时,调用updatechartdata()槽函数来更新温度曲线数据,同时控制数据量不超过30个点。
在updatechartdata()函数中,使用了qrand()函数来生成随机的温度数据,模拟动态变化的效果。可以根据实际情况修改此函数的实现方式。
最后,将图表添加到qchartview控件中,并启用抗锯齿功能以提高显示质量。
【2】设置曲线可见范围为了保证曲线显示一直在可见范围内,可以添加如下代码:
// 使图表自适应大小,确保曲线始终可见 m_chart- >createdefaultaxes(); m_chart- >axisx()- >setrange(0, 30); m_chart- >axisy()- >setrange(0, 60);这段代码的作用是让图表自适应大小,并设置横轴范围为0到30,纵轴范围为0到60。这样当新数据点增加到图表之外时,图表会自动调整大小和范围,以确保曲线始终可见。
完整的mainwindow.cpp代码如下所示:
#include mainwindow.h #include ui_mainwindow.h mainwindow::mainwindow(qwidget *parent) : qmainwindow(parent), ui(new ui::mainwindow), m_timer(new qtimer(this)), m_chart(new qchart()), m_series1(new qlineseries()), m_series2(new qlineseries()), m_series3(new qlineseries()), m_timecount(0) { ui- >setupui(this); // 设置图表标题 m_chart- >settitle(temperature data); // 创建温度曲线图1并设置属性 m_series1- >setname(tr(device 1)); m_series1- >setcolor(qt::red); m_series1- >setpen(qpen(qt::red, 2)); m_chart- >addseries(m_series1); // 创建温度曲线图2并设置属性 m_series2- >setname(tr(device 2)); m_series2- >setcolor(qt::green); m_series2- >setpen(qpen(qt::green, 2)); m_chart- >addseries(m_series2); // 创建温度曲线图3并设置属性 m_series3- >setname(tr(device 3)); m_series3- >setcolor(qt::blue); m_series3- >setpen(qpen(qt::blue, 2)); m_chart- >addseries(m_series3); // 设置横轴属性 qvalueaxis *axisx = new qvalueaxis; axisx- >setrange(0, 30); axisx- >settitletext(time (s)); m_chart- >addaxis(axisx, qt::alignbottom); m_series1- >attachaxis(axisx); m_series2- >attachaxis(axisx); m_series3- >attachaxis(axisx); // 设置纵轴属性 qvalueaxis *axisy = new qvalueaxis; axisy- >setrange(0, 60); axisy- >settitletext(temperature (℃)); m_chart- >addaxis(axisy, qt::alignleft); m_series1- >attachaxis(axisy); m_series2- >attachaxis(axisy); m_series3- >attachaxis(axisy); // 使图表自适应大小,确保曲线始终可见 m_chart- >createdefaultaxes(); m_chart- >axisx()- >setrange(0, 30); m_chart- >axisy()- >setrange(0, 60); // 定时更新数据 connect(m_timer, &qtimer::timeout, this, &mainwindow::updatechartdata); m_timer- >start(1000); // 每隔1秒钟更新一次数据 // 将图表添加到chartview中 ui- >chartview- >setchart(m_chart); ui- >chartview- >setrenderhint(qpainter::antialiasing); } mainwindow::~mainwindow() { delete ui; } void mainwindow::updatechartdata() { // 更新时间计数 m_timecount++; // 在温度曲线上增加一个点,模拟温度数据变化 qpointf p1(m_timecount, qrand() % 10 + 20); qpointf p2(m_timecount, qrand() % 10 + 30); qpointf p3(m_timecount, qrand() % 10 + 40); m_series1- >append(p1); m_series2- >append(p2); m_series3- >append(p3); // 清除多余的点,只保留最新的30个数据点 if (m_series1- >count() > 30) { m_series1- >removepoints(0, 1); } if (m_series2- >count() > 30) { m_series2- >removepoints(0, 1); } if (m_series3- >count() > 30) { m_series3- >removepoints(0, 1); } }【3】实现鼠标交互拖动要实现折线图的横坐标可以拖动,可以设置qchartview的交互模式为拖拽,在构造函数中添加如下代码:
// 设置 chartview 交互模式为拖拽 ui- >chartview- >setrubberband(qchartview::horizontalrubberband); ui- >chartview- >setrenderhint(qpainter::antialiasing); ui- >chartview- >setdragmode(qgraphicsview::scrollhanddrag);这样用户就可以通过鼠标左键在横轴上拖拽来改变曲线图的可见范围。同时,还需要在mainwindow.cpp中添加横坐标的范围更新函数updateaxisrange(),用于在拖拽时更新横坐标的范围。
完整的mainwindow.cpp代码如下所示:
#include mainwindow.h #include ui_mainwindow.h mainwindow::mainwindow(qwidget *parent) : qmainwindow(parent), ui(new ui::mainwindow), m_timer(new qtimer(this)), m_chart(new qchart()), m_series1(new qlineseries()), m_series2(new qlineseries()), m_series3(new qlineseries()), m_timecount(0) { ui- >setupui(this); // 设置图表标题 m_chart- >settitle(temperature data); // 创建温度曲线图1并设置属性 m_series1- >setname(tr(device 1)); m_series1- >setcolor(qt::red); m_series1- >setpen(qpen(qt::red, 2)); m_chart- >addseries(m_series1); // 创建温度曲线图2并设置属性 m_series2- >setname(tr(device 2)); m_series2- >setcolor(qt::green); m_series2- >setpen(qpen(qt::green, 2)); m_chart- >addseries(m_series2); // 创建温度曲线图3并设置属性 m_series3- >setname(tr(device 3)); m_series3- >setcolor(qt::blue); m_series3- >setpen(qpen(qt::blue, 2)); m_chart- >addseries(m_series3); // 设置横轴属性 qvalueaxis *axisx = new qvalueaxis; axisx- >setrange(0, 30); axisx- >settitletext(time (s)); m_chart- >addaxis(axisx, qt::alignbottom); m_series1- >attachaxis(axisx); m_series2- >attachaxis(axisx); m_series3- >attachaxis(axisx); // 设置纵轴属性 qvalueaxis *axisy = new qvalueaxis; axisy- >setrange(0, 60); axisy- >settitletext(temperature (℃)); m_chart- >addaxis(axisy, qt::alignleft); m_series1- >attachaxis(axisy); m_series2- >attachaxis(axisy); m_series3- >attachaxis(axisy); // 使图表自适应大小,确保曲线始终可见 m_chart- >createdefaultaxes(); m_chart- >axisx()- >setrange(0, 30); m_chart- >axisy()- >setrange(0, 60); // 设置 chartview 交互模式为拖拽 ui- >chartview- >setrubberband(qchartview::horizontalrubberband); ui- >chartview- >setrenderhint(qpainter::antialiasing); ui- >chartview- >setdragmode(qgraphicsview::scrollhanddrag); // 定时更新数据 connect(m_timer, &qtimer::timeout, this, &mainwindow::updatechartdata); m_timer- >start(1000); // 每隔1秒钟更新一次数据 // 将图表添加到chartview中 ui- >chartview- >setchart(m_chart); } mainwindow::~mainwindow() { delete ui; } void mainwindow::updatechartdata() { // 更新时间计数 m_timecount++; // 在温度曲线上增加一个点,模拟温度数据变化 qpointf p1(m_timecount, qrand() % 10 + 20); qpointf p2(m_timecount, qrand() % 10 + 30); qpointf p3(m_timecount, qrand() % 10 + 40); m_series1- >append(p1); m_series2- >append(p2); m_series3- >append(p3); // 清除多余的点,只保留最新的30个数据点 if (m_series1- >count() > 30) { m_series1- >removepoints(0, 1); } if (m_series2- >count() > 30) { m_series2- >removepoints(0, 1); } if (m_series3- >count() > 30) { m_series3- >removepoints(0, 1); } // 更新横轴范围 updateaxisrange(); } void mainwindow::updateaxisrange() { // 获取横轴范围 qreal minx = std::numeric_limits::max(); qreal maxx = std::numeric_limits::min(); foreach (qabstractseries *series, m_chart- >series()) { qxyseries *xyseries = static_cast(series); qpointf p1 = xyseries- >at(0); qpointf p2 = xyseries- >at(xyseries- >count() - 1); if (p1.x() maxx) { maxx = p2.x(); } } // 更新横轴范围 m_chart- >axisx()- >setrange(minx, maxx); }为了更新横坐标的范围,需要在mainwindow中添加了一个新函数updateaxisrange()。该函数会在数据更新时被调用来计算最新的横轴范围,以更新折线图的显示。
三、实现代码(2)qwidget当前这份完整代码实现了一个动态折线图的绘制,是一个典型的qt charts应用程序。通过使用qlineseries类、qvalueaxis类和qchart类来创建并显示温度随时间变化的折线图。
第一步:先创建了主窗口,其中包含一个qchartview控件,用于显示温度曲线图。在构造函数中,设置了一些基本属性,比如标题、横纵坐标的范围和名称等,并为每个设备创建了一个qlineseries对象,用于存储温度数据。
第二步:将这些qlineseries对象添加到qchart对象中。接着,将qvalueaxis对象添加到qchart中,设置其范围和名称,并将qlineseries对象与其关联。最后,将qchart对象添加到qchartview中,以便在界面上显示折线图。
第三步:在updatechartdata()函数中,定时器每隔1秒钟触发一次,用于更新温度数据,并通过调用qlineseries类的append()函数向qlineseries对象中添加新的温度数据点。同时,使用removepoints()函数删除旧的数据点,以保持折线图中显示的数据点不超过30个。在添加或删除数据时,使用updateaxisrange()函数更新横坐标的范围,以便将折线图自适应地缩放到当前数据范围内。
第四步:重载了updateaxisrange()函数,根据qlineseries对象的数据点计算出横坐标的最小值和最大值,并通过调用qchart类的axisx()->setrange()函数更新qvalueaxis对象的范围。
【1】widget.cpp代码#include widget.h #include ui_widget.h widget::widget(qwidget *parent) : qwidget(parent) , ui(new ui::widget) { ui- >setupui(this); this- >setwindowtitle(温度数据可视化采集系统); m_timer=new qtimer(this); m_chart=new qchart(); m_series1=new qlineseries(); m_series2=new qlineseries(); m_series3=new qlineseries(); m_timecount=0; // 创建温度曲线图1并设置属性 m_series1- >setname(tr(设备1)); // m_series1- >setcolor(qt::red); // m_series1- >setpen(qpen(qt::red, 2)); m_chart- >addseries(m_series1); // 创建温度曲线图2并设置属性 m_series2- >setname(tr(设备2)); // m_series2- >setcolor(qt::green); // m_series2- >setpen(qpen(qt::green, 2)); m_chart- >addseries(m_series2); // 创建温度曲线图3并设置属性 m_series3- >setname(tr(设备3)); // m_series3- >setcolor(qt::blue); // m_series3- >setpen(qpen(qt::blue, 2)); m_chart- >addseries(m_series3); // 设置横轴属性 qvalueaxis *axisx = new qvalueaxis; axisx- >setrange(0, 30); axisx- >settitletext(时间 (s)); m_chart- >addaxis(axisx, qt::alignbottom); m_series1- >attachaxis(axisx); m_series2- >attachaxis(axisx); m_series3- >attachaxis(axisx); // 设置纵轴属性 qvalueaxis *axisy = new qvalueaxis; axisy- >setrange(0, 60); axisy- >settitletext(温度 (℃)); m_chart- >addaxis(axisy, qt::alignleft); m_series1- >attachaxis(axisy); m_series2- >attachaxis(axisy); m_series3- >attachaxis(axisy); // 使图表自适应大小,确保曲线始终可见 m_chart- >createdefaultaxes(); m_chart- >axisx()- >setrange(0, 30); m_chart- >axisy()- >setrange(0, 60); // 定时更新数据 connect(m_timer, &qtimer::timeout, this, &widget::updatechartdata); // 将图表添加到chartview中 qchartview* chartview = new qchartview(m_chart); // 设置 chartview 交互模式为拖拽 chartview- >setrubberband(qchartview::horizontalrubberband); chartview- >setrenderhint(qpainter::antialiasing); chartview- >setdragmode(qgraphicsview::scrollhanddrag); chartview- >setrenderhint(qpainter::antialiasing); //将视图添加到布局 ui- >view_verticallayout- >addwidget(chartview); } widget::~widget() { delete ui; } void widget::updatechartdata() { // 更新时间计数 m_timecount++; // 在温度曲线上增加一个点,模拟温度数据变化 qpointf p1(m_timecount, qrand() % 10 + 20); qpointf p2(m_timecount, qrand() % 10 + 30); qpointf p3(m_timecount, qrand() % 10 + 40); m_series1- >append(p1); m_series2- >append(p2); m_series3- >append(p3); // 清除多余的点,只保留最新的30个数据点 if (m_series1- >count() > 30) { m_series1- >removepoints(0, 1); } if (m_series2- >count() > 30) { m_series2- >removepoints(0, 1); } if (m_series3- >count() > 30) { m_series3- >removepoints(0, 1); } // 更新横轴范围 updateaxisrange(); } void widget::updateaxisrange() { // 获取横轴范围 qreal minx = std::numeric_limits::max(); qreal maxx = std::numeric_limits::min(); foreach (qabstractseries *series, m_chart- >series()) { qxyseries *xyseries = static_cast(series); qpointf p1 = xyseries- >at(0); qpointf p2 = xyseries- >at(xyseries- >count() - 1); if (p1.x() maxx) { maxx = p2.x(); } } // 更新横轴范围 m_chart- >axisx()- >setrange(minx, maxx); } //开始采集 void widget::on_pushbutton_start_clicked() { m_timer- >start(1000); // 每隔1秒钟更新一次数据 } //停止采集 void widget::on_pushbutton_stop_clicked() { m_timer- >stop(); //停止定时器 }【2】widget.h代码#ifndef widget_h #define widget_h #include // 包含line chart需要的头文件 #include #include #include #include #include #include #include // 引用命名空间 qt_charts_use_namespace qt_begin_namespace namespace ui { class widget; } qt_end_namespace class widget : public qwidget { q_object public: widget(qwidget *parent = nullptr); ~widget(); private slots: void updatechartdata(); // 更新数据槽函数 void updateaxisrange(); void on_pushbutton_start_clicked(); void on_pushbutton_stop_clicked(); private: ui::widget *ui; qtimer *m_timer; // 定时器 qchart *m_chart; // 图表指针 qlineseries *m_series1; // 设备1温度曲线 qlineseries *m_series2; // 设备2温度曲线 qlineseries *m_series3; // 设备3温度曲线 int m_timecount; // 时间计数 }; #endif // widget_h【3】ui文件代码
一文详解光电二极管的基本等效电路
e络盟针对工业自动化与控制应用提供TE Connectivity互连产品解决方案
采用氮氧化物检测仪实现对氮氧化物排放的有效监控
RFID超高频物联网安卓手持终端P6051描述
知豆领衔中国首次新能源整车众筹
Qt(C++)使用QChart动态显示3个设备的温度变化曲线
PROTEL技术大全之第三篇
RF电路板分区设计的问题探讨
深圳公交搭载人脸识别系统 让市民享受到更加便利的出行服务
如何轻松掌握机器学习概念和在工业自动化中的应用
锐捷交换机还原初始设置,一招搞定
谋求新增长点,炬芯联手LeMaker推开源硬件平台
西部数据推出新3个G产品系列解决方案,满足快速传输和高容量需求
液晶电视面板供应量或将再次减少?
干货:电能质量问题引起的常见现象
智源学者候选名单公布,重大研究方向5至7个
什么是氮化镓,氮化镓有哪些好处
基于AW3208的手机快速充电方案
ESP32开源示波器设计综述
空间站系统的操作界面首次亮相