Qt应用开发(拓展篇)——示波器/图表 QCustomPlot

news2025/1/12 2:48:52

一、介绍

        QCustomPlot是一个用于绘图和数据可视化的Qt C++小部件。它没有进一步的依赖关系,提供友好的文档帮助。这个绘图库专注于制作好看的,出版质量的2D绘图,图形和图表,以及为实时可视化应用程序提供高性能。
        QCustomPlot可以导出各种格式,如矢量化的PDF文件和光栅化的图像,如PNG, JPG和BMP。QCustomPlot是用于在应用程序中显示实时数据以及为其他媒体生成高质量图的解决方案。

二、配置

1)下载

官方网站icon-default.png?t=N6B9http://www.qcustomplot.com/

        从官网下载文件,选择2.1版本以上,因为这会开始支持Qt6了。可以选择源文件+实例+说明文档全部下载,或者选择下载单动态库或纯源码,文件不大建议全部下载。

 2)QtCreator配置

        新建一个Qt Widgets Application工程。

         把下载好的qcustomplot.h和qcustomplot.cpp放到工程下,右击项目,添加现有文件。

        对话框中选择选择qcustomplot.h和qcustomplot.cpp文件添加到项目中,并在pro文件中添加Qt += printsupport。

        双击mainwindows.ui进入Designer界面,新建一个widget部件。

         右击widget部件,选择提升为...。

         在类名称里面输入QCustomPlot,选择“添加”,然后选择“提升”。

        这里要注意头文件路径,如果你是放在最外层(和pro文件同级),直接默认值就行。如果是放在某文件夹下,比如新建了一个custom文件夹并放置在里面,那么头文件这一栏应该是“custom/qcustomplot.h”。

 

         提升之后,widget类已经被改成QCustomPlot。

         在mianwindows.cpp构造函数添加如下demo代码。        

// add two new graphs and set their look:
    ui->widget->addGraph();
    ui->widget->graph(0)->setPen(QPen(Qt::blue)); // line color blue for first graph
    ui->widget->graph(0)->setBrush(QBrush(QColor(0, 0, 255, 20))); // first graph will be filled with translucent blue
    ui->widget->addGraph();
    ui->widget->graph(1)->setPen(QPen(Qt::red)); // line color red for second graph
    // generate some points of data (y0 for first, y1 for second graph):
    QVector<double> x(251), y0(251), y1(251);
    for (int i=0; i<251; ++i)
    {
      x[i] = i;
      y0[i] = qExp(-i/150.0)*qCos(i/10.0); // exponentially decaying cosine
      y1[i] = qExp(-i/150.0);              // exponential envelope
    }
    // configure right and top axis to show ticks but no labels:
    // (see QCPAxisRect::setupFullAxesBox for a quicker method to do this)
    ui->widget->xAxis2->setVisible(true);
    ui->widget->xAxis2->setTickLabels(false);
    ui->widget->yAxis2->setVisible(true);
    ui->widget->yAxis2->setTickLabels(false);
    // make left and bottom axes always transfer their ranges to right and top axes:
    connect(ui->widget->xAxis, SIGNAL(rangeChanged(QCPRange)), ui->widget->xAxis2, SLOT(setRange(QCPRange)));
    connect(ui->widget->yAxis, SIGNAL(rangeChanged(QCPRange)), ui->widget->yAxis2, SLOT(setRange(QCPRange)));
    // pass data points to graphs:
    ui->widget->graph(0)->setData(x, y0);
    ui->widget->graph(1)->setData(x, y1);
    // let the ranges scale themselves so graph 0 fits perfectly in the visible area:
    ui->widget->graph(0)->rescaleAxes();
    // same thing for graph 1, but only enlarge ranges (in case graph 1 is smaller than graph 0):
    ui->widget->graph(1)->rescaleAxes(true);
    // Note: we could have also just called ui->widget->rescaleAxes(); instead
    // Allow user to drag axis ranges with mouse, zoom with mouse wheel and select graphs by clicking:
    ui->widget->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectPlottables);

        编译构建项目成功后,执行即可看到demo图表。

三、常用功能详解

1)曲线

        使用addGraph()方法新建曲线,返回一个QCPGraph对象指针,后续使用此指针或者根据新建的顺序传入索引ui->widget->graph(index)对曲线动作。

        建议使用保存对象指针方法操作曲线,因为索引不直观。而且当新建两条曲线的时候,删除第一条,第二条索引会从1变成0,会有误操作的风险。

QCPGraph *graph1 = ui->plot->addGraph();

        使用setData()方法设置曲线坐标数据,坐标数据使用QVector封装,使用此方法会覆盖原先的曲线。注意这里x和y的动态数组长度要一致,否则控制台会报错并失效。

QVector<double> x0(251), y0(251);
for (int i=0; i<251; ++i)
{
   x[i] = i;
   y0[i] = qExp(-i/150.0)*qCos(i/10.0);
}
ui->plot->graph(0)->setData(x0,y0);//写入数据

        使用addData()方法在原先基础上添加数据,适用于动态曲线,当然如果一直重新setData也是可以,不建议这么做。

ui->plot->graph(0)->addData(x0, y0)

        使用clear()清空数据,但是曲线还保留着。

ui->plot->graph(0)->data()->clear();

        使用setName()方法设置曲线名称,name方法返回曲线名称。

ui->plot->graph(0)->setName(QString("graph1"));
qDebug()<<ui->Plot->graph(0)->name();

        使用removeGraph()方法传入QCPGraph指针或者索引移除曲线。

ui->plot->removeGraph(0);
ui->plot->removeGraph(graph1);

         设置曲线画笔颜色、宽度、样式。

ui->plot->graph(0)->setPen(QPen(QColor(120, 120, 120), 2));

        设置曲线使用刷子。

ui->plot->graph(1)->setBrush(QColor(200, 200, 200, 20));

        使用setChannelFillGraph()把通道2包含在1里面,这样刷子颜色就不会透视。

QCPGraph *graph2 = ui->widget->addGraph();
graph2->setData(x2, y2);
graph2->setPen(Qt::NoPen);
graph2->setBrush(QColor(200, 200, 200, 20));
graph2->setChannelFillGraph(graph1);

 

         使用setScatterStyle()设置曲线散点的样式。

ui->plot->graph(0)->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssCircle, QPen(Qt::black, 1.5), QBrush(Qt::white), 9));

2)柱状图

        实例化QCPBars()

QCPBars *bars1 = new QCPBars(ui->widget->xAxis, ui->widget->yAxis);

         使用setWidth()设置柱状图宽度

bars1->setWidth(10);

        使用setPen()设置画笔

bars1->setPen(QPen(QColor(120, 120, 120), 2));

        使用setBrush()设置刷子颜色填充。

bars1->setBrush(QColor(10, 140, 70, 160));

        使用moveAbove()设置栏2在1的上方。

bars2->moveAbove(bars1);

3)坐标轴

        使用setVisible()方法设置是否显示。

ui->plot->xAxis2->setVisible(true);
ui->plot->yAxis2->setVisible(true);

        使用setTickLabels()方法设置是否显示刻度。

ui->widget->xAxis2->setTickLabels(false);
ui->widget->yAxis2->setTickLabels(false);

         使用rescaleAxes()方法设置自适应坐标轴,防止因为坐标轴范围过长而出现大量无数据地带

ui->Plot->graph(0)->rescaleAxes();

         使用setRange()设置坐标轴范围,使用range()获取坐标轴范围数值。

ui->plot->xAxis->setRange(0, 100);
ui->plot->yAxis->setRange(0, 100);
QCPRange XAxis_Range=ui->plot->xAxis->range();

        缩放、自适应等会触发rangeChanged()信号,同步使用setRange(),保证上下、左右坐标一致。

connect(ui->plot->xAxis, SIGNAL(rangeChanged(QCPRange)), ui->plot->xAxis2, SLOT(setRange(QCPRange)));
connect(ui->plot->yAxis, SIGNAL(rangeChanged(QCPRange)), ui->plot->yAxis2, SLOT(setRange(QCPRange)));

3)样式

        使用setTickLabelColor()设置坐标轴标签的颜色。

ui->plot->xAxis->setTickLabelColor(Qt::red);
ui->plot->yAxis->setTickLabelColor(Qt::red);

         使用setTickPen()设置含标签的刻度的画笔的颜色、线宽和样式。

ui->widget->xAxis->setTickPen(QPen(Qt::red, 1));
ui->widget->yAxis->setTickPen(QPen(Qt::red, 1));

         使用setSubTickPen()设置不含标签的刻度的画笔的颜色、线宽和样式。

ui->widget->xAxis->setSubTickPen(QPen(Qt::red, 1));
ui->widget->yAxis->setSubTickPen(QPen(Qt::red, 1));

         使用setBasePen()设置坐标轴画笔的颜色、线宽和样式。

ui->plot->xAxis->setBasePen(QPen(Qt::red, 1));
ui->plot->yAxis->setBasePen(QPen(Qt::red, 1));

         使用setSubGridVisible()设置是否显示二级网格。

ui->plot->xAxis->grid()->setSubGridVisible(true);
ui->plot->yAxis->grid()->setSubGridVisible(true);

  

        使用setPen()设置网格的画笔的颜色、线宽和样式。

ui->plot->xAxis->grid()->setPen(QPen(QColor(140, 140, 140), 1, Qt::DotLine));
ui->plot->yAxis->grid()->setPen(QPen(QColor(140, 140, 140), 1, Qt::DotLine));

        使用setSubGridPen()设置二级网格的画笔的颜色、线宽和样式。

ui->plot->xAxis->grid()->setSubGridPen(QPen(QColor(80, 80, 80), 1, Qt::DotLine));
ui->plot->yAxis->grid()->setSubGridPen(QPen(QColor(80, 80, 80), 1, Qt::DotLine));

         使用setZeroLinePen()设置零线的画笔的颜色、线宽和样式。

ui->plot->xAxis->grid()->setZeroLinePen(Qt::NoPen);
ui->plot->yAxis->grid()->setZeroLinePen(Qt::NoPen);

        使用setBackground()设置背景颜色,设置渐变色,也可以直接使用图片,纯色刷子来当背景。

QLinearGradient plotGradient;
plotGradient.setStart(0, 0);
plotGradient.setFinalStop(0, 350);
plotGradient.setColorAt(0, QColor(80, 80, 80));
plotGradient.setColorAt(1, QColor(50, 50, 50));
ui->plot->setBackground(plotGradient);

QLinearGradient axisRectGradient;
axisRectGradient.setStart(0, 0);
axisRectGradient.setFinalStop(0, 350);
axisRectGradient.setColorAt(0, QColor(80, 80, 80));
axisRectGradient.setColorAt(1, QColor(30, 30, 30));
ui->widget->axisRect()->setBackground(axisRectGradient);

         使用setUpperEnding()设置上轴结束的样式。

ui->plot->xAxis->setUpperEnding(QCPLineEnding::esSpikeArrow);
ui->plot->yAxis->setUpperEnding(QCPLineEnding::esSpikeArrow);

4)图例

        使用setVisible()设置图例是否显示。

ui->plot->legend->setVisible(true);

        使用setFillOrder()设置图例信息的水平方向。

ui->plot->legend->setFillOrder(QCPLayoutGrid::foColumnsFirst);

         使用addElement()设置图例显示的坐标、位置和比例。

ui->plot->plotLayout()->addElement(1 , 0, ui->plot->legend);

        使用setBorderPen()设置图例边框颜色、线宽、样式。

ui->plot->legend->setBorderPen(QPen(QColor(140, 140, 140), 1, Qt::DotLine));

         使用setRowStretchFactor()设置显示比例,图例所在框的大小。

ui->plot->plotLayout()->setRowStretchFactor(1, 0.001);

4)其他

        使用setInteractions()方法设置交互策略

ui->Plot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectPlottables);
//放大拖拽选中等枚举
enum Interaction { iRangeDrag         = 0x001 //左键点击可拖动
                   ,iRangeZoom        = 0x002 //范围可通过鼠标滚轮缩放
                   ,iMultiSelect      = 0x004 //可选中多条曲线
                   ,iSelectPlottables = 0x008 //线条可选中
                   ,iSelectAxes       = 0x010 //坐标轴可选
                   ,iSelectLegend     = 0x020 //图例是可选择的
                   ,iSelectItems      = 0x040 //可选择项(矩形、箭头、文本项等
                   ,iSelectOther      = 0x080 //所有其他对象都是可选的
                 };

        使用replot()重新启动绘制,当你需要一条动态曲线的时候,除了动态的addData(),还需要不断的使用replot()进行后续的绘制。

ui->plot->replot();

         保存成Pdf、Png、Jpg、Bmp格式文件。

bool savePdf (const QString &fileName, int width=0, int height=0, QCP::ExportPen exportPen=QCP::epAllowCosmetic, const QString &pdfCreator=QString(), const QString &pdfTitle=QString())
 
bool savePng (const QString &fileName, int width=0, int height=0, double scale=1.0, int quality=-1, int resolution=96, QCP::ResolutionUnit resolutionUnit=QCP::ruDotsPerInch)
 
bool saveJpg (const QString &fileName, int width=0, int height=0, double scale=1.0, int quality=-1, int resolution=96, QCP::ResolutionUnit resolutionUnit=QCP::ruDotsPerInch)
 
bool saveBmp (const QString &fileName, int width=0, int height=0, double scale=1.0, int resolution=96, QCP::ResolutionUnit resolutionUnit=QCP::ruDotsPerInch)

        QPen样式

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/917696.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

温湿度传感器之Modbus TCP相比较Modbus RTU的优势

1) 当多个网关共同接一个后台服务器&#xff0c;而一个网关下挂接多个485设备时&#xff0c;如果不同的网关挂接同样地址号的485设备时那么后台服务器无法区分是哪个485从设备&#xff0c;并且最多只能限制485设备个数254个&#xff0c;而modbus-tcp协议包含自定义报文头4个字节…

什么是NetDevOps

NetDevOps 是一种新兴的方法&#xff0c;它结合了 NetOps 和 DevOps 的流程&#xff0c;即将网络自动化集成到开发过程中。NetDevOps 的目标是将虚拟化、自动化和 API 集成到网络基础架构中&#xff0c;并实现开发和运营团队之间的无缝协作。 开发运营&#xff08;DevOps&…

网站和API支持HTTPS,最好在Nginx上配置

随着我们网站用户的增多&#xff0c;我们会逐渐意识到HTTPS加密的重要性。在不修改现有代码的情况下&#xff0c;要从HTTP升级到HTTPS&#xff0c;让Nginx支持HTTPS是个很好的选择。今天我们来讲下如何从Nginx入手&#xff0c;从HTTP升级到HTTPS&#xff0c;同时支持静态网站和…

GEE-PIE遥感大数据处理技术

随着航空、航天、近地空间等多个遥感平台的不断发展&#xff0c;近年来遥感技术突飞猛进。由此&#xff0c;遥感数据的空间、时间、光谱分辨率不断提高&#xff0c;数据量也大幅增长&#xff0c;使其越来越具有大数据特征。对于相关研究而言&#xff0c;遥感大数据的出现为其提…

机器学习深度学习——针对序列级和词元级应用微调BERT

&#x1f468;‍&#x1f393;作者简介&#xff1a;一位即将上大四&#xff0c;正专攻机器学习的保研er &#x1f30c;上期文章&#xff1a;机器学习&&深度学习——NLP实战&#xff08;自然语言推断——注意力机制实现&#xff09; &#x1f4da;订阅专栏&#xff1a;机…

独立站怎么搭建?看这一篇就够了!强烈建议收藏!

独立站是跨境卖家对外销售的一个重要渠道&#xff0c;也是品牌塑造和品牌宣传的重要阵地。那么新手如何从0到1搭建出一个属于自己的独立站呢&#xff1f; 01.购买域名&#xff1a; 域名就相当于是一个网站的门牌号&#xff0c;是独立站的重要组成部分。卖家可以选择自己注册&…

C语言:指针(超深度讲解)

目录 指针&#xff1a; 学习目标&#xff1a; 指针可以理解为&#xff1a; 字符指针&#xff1a; 定义&#xff1a;字符指针 char*。 字符指针的使用&#xff1a; 练习&#xff1a; 指针数组&#xff1a; 概念&#xff1a;指针数组是一个存放指针的数组。 实现模拟二维…

【0基础入门Python Web笔记】四、python 之计算器的进阶之路

四、python 之计算器的进阶之路 往期导航越来越智能的加法计算器加减乘除计算器来点课程作业&#xff1f;更多实战项目可进入下方官网 往期导航 一、python 之基础语法、基础数据类型、复合数据类型及基本操作 二、python 之逻辑运算和制流程语句 三、python 之函数以及常用内…

服务器中了Cylance勒索病毒,数据该怎么恢复?

近日&#xff0c;在市面上出现了一种名为Cylance的勒索病毒。经过云天数据恢复中心技术工程师对比分析后发现&#xff0c;该病毒不属于已知的任何勒索病毒家族中的成员&#xff0c;属于一种新型的勒索病毒&#xff0c;那接下来我们分析一下这种勒索病毒。 中了Cylance勒索病毒的…

AVL树Java实现

文章目录 AVL树(平衡二插搜索树)1.概念二插搜索树AVL树的基本概念 2.AVL数的实现定义AVL树AVL树的插入AVL树的旋转右单旋左单旋左右双旋右左双旋 删除元素 3. 验证AVL树4.AVL树性能分析 AVL树(平衡二插搜索树) 1.概念 二插搜索树 要想了解AVL树&#xff0c;就得先知道二插搜…

HIDS-wazuh 的配置和防御

目录 安装wazuh 常用内容 检测sql注入 主动响应 安装wazuh 本地测试的话建议用ova文件&#xff0c;直接导入虚拟机就能用了 官网&#xff1a;Virtual Machine (OVA) - Installation alternatives 常用内容 目录位置&#xff1a;/etc/ossec 配置文件&…

装箱和拆箱

1. 概念 装箱 将值类型转换成等价的引用类型 装箱的步骤 拆箱 将一个已装箱的引用类型转换为值类型&#xff0c;拆箱操作需要声明拆箱后转换的类型 拆箱的步骤 1&#xff09;获取已装箱的对象的地址 2&#xff09;将值从堆上的对象中复制到堆栈上的值变量中 2. 总结 装箱和拆箱…

表现层消息一致性处理

设计表现层返回结果的模型类&#xff0c; 用于后端与前端进行数据格式统一&#xff0c;也称为前后端数据协议 Data public class R {private Boolean flag;private Object data;private String msg;public R(){}public R(Boolean flag){this.flag flag;}public R(Boolean fla…

如何使用NLP库解析Python中的文本

Python是一种强大的面向对象的编程&#xff08;object-oriented programming&#xff0c;OOP&#xff09;语言&#xff0c;在人工智能领域有着广泛的用途。正是鉴于其实用性&#xff0c;以Google为首的大型科技公司&#xff0c;已经对其开发了Tensorflow等代码库&#xff0c;帮…

相交链表00

题目链接 相交链表 题目描述 注意点 保证 整个链式结构中不存在环函数返回结果后&#xff0c;链表必须 保持其原始结构如果 listA 和 listB 没有交点&#xff0c;intersectVal 为 0 解答思路 两个链表从头开始遍历&#xff0c;如果其是在同一个位置处相交&#xff0c;则在…

(AcWing)没有上司的舞会

Ural 大学有 NN 名职员&#xff0c;编号为 1∼N。 他们的关系就像一棵以校长为根的树&#xff0c;父节点就是子节点的直接上司。 每个职员有一个快乐指数&#xff0c;用整数 Hi 给出&#xff0c;其中 1≤i≤N。 现在要召开一场周年庆宴会&#xff0c;不过&#xff0c;没有职…

智能问答FAQ的原始问答数据怎么整理?

整理智能问答FAQ的原始数据是构建一个智能问答系统的重要步骤之一。 如何整理原始问答数据以及如何将其转化为智能问答系统 1. 收集原始数据 收集原始数据是整理智能问答FAQ的第一步。可以从以下途径收集原始数据&#xff1a; 网络搜索&#xff1a;通过搜索引擎、论坛、社交…

小白到运维工程师自学之路 第七十九集 (基于Jenkins自动打包并部署Tomcat环境)2

紧接上文 4、新建Maven项目 clean package -Dmaven.test.skiptrue 用于构建项目并跳过执行测试 拉到最后选择构建后操作 SSH server webExec command scp 192.168.77.18:/root/.jenkins/workspace/probe/psi-probe-web/target/probe.war /usr/local/tomcat/webapps/ /usr/loca…

伦敦银和伦敦金的区别

伦敦银河伦敦金并称贵金属交易市场的双璧&#xff0c;一般投资贵金属的投资者其实不是交易伦敦金就是交易伦敦银。相信经过一段时间的学习和投资&#xff0c;不少投资者都能分辨二者的区别。下面我们就来谈谈伦敦银和伦敦金有什么异同&#xff0c;他们在投资上是否有差别。 交易…

股票预测和使用LSTM(长期-短期-记忆)的预测

一、说明 准确预测股市走势长期以来一直是投资者和交易员难以实现的目标。虽然多年来出现了无数的策略和模型&#xff0c;但有一种方法最近因其能够捕获历史数据中的复杂模式和依赖关系而获得了显着的关注&#xff1a;长短期记忆&#xff08;LSTM&#xff09;。利用深度学习的力…