Qcustomplot与QCharts的使用

本文对比了Qt自带的QChart模块与开源库QCustomPlot在图表绘制上的优缺点,指出QCustomPlot在处理大量数据时性能更好,适合绘制复杂图形和提供交互功能。对于小规模和定制化需求,QPaint是个不错的选择,而QCustomPlot在数据量较大时更具优势。
摘要由CSDN通过智能技术生成

=一、 前言=
由于Qt本身的model、delegate结构,我们在遇到图表等内容时也通常使用该方式直接绘制,优点是可以随心所欲的绘制任何图形,但是缺点是代码量较大,影响开发效率。
=二、 简介=
其中Qt本身也为我们提供了绘制图表的QChart模块,且该模块功能强大,能够绘制包含折线、曲线、饼图、棒图、散点图、雷达图等各种常用的图表,在QT5.7版本以前该模块一直属于收费项目,只有商业版本才能使用,但是5.7版本后开放了Qt Charts(二维图表)Qt Data Visualization(三维图表)的权限。但是QChart一般只能处理2000个点以内的数据,如果数据过多就会存在刷新卡顿的问题。
而QT中常用的第三方工具为QCustomPlot和Qwt,其中Qwt功能比较全面但配置比较麻烦,而qcustomplot小巧玲珑,简单易用,上手快,只有两个源文件可以直接添加进工程,修改源代码也比较方便。本文仅介绍QCustomPlot工具,QCustomPlot专注于制作美观、高品质的2D图表,且可以导出各种格式的图片,如矢量化的PDF文件和PNG/JPG/BMP等文件。
=三、 安装与使用=
<1> QChart为Qt本身自带的模块,因此在创建项目时勾选Charts模块,在需要使用该模块的类UI文件中添加Widget控件,将Widget提升为QChartView类。
 {F2291160}
但是UI文件中需要增加命名空间,不然会报编译错误,而由于在UI文件中添加内容每次构建都需要修改,因此在头文件中增加,在头文件的#include “ui_xxxx.h”前增加
命名空间:
#include <QtCharts>
QT_CHARTS_USE_NAMESPACE /* 增加QCharts命名空间 */

#include “ui_xxxx.h”
<2> QCustomPlot虽然为开源第三方库,但是由于其专注与2D的图表绘制,因此其内容小巧(头文件300k,源文件1300k),仅需下载qcustomplot的头文件与源文件,加载到项目中。(Ps:因为qcustomplot支持文件输出与打印,因此如果要使用该功能则需要在项目中勾选 printf support模块,如果不需要或不想引入printf support模块则可以在源码中删除相关内容)。在所需要使用qcustomplot中的类中包含qcustomplot头文件即可.
下载地址:https://www.qcustomplot.com/index.php/introduction
=四、 绘图示例=
以项目中设备设置中的的太阳能设备数据绘制为例,展示QCharts和QCustomPlot的使用方法,绘制一个月的电池电量变化数据。
<1>使用QCharts绘制
```
lang=C,
#include "QtChartApplicatin.h"
#include <QChartView>
#include <QLineSeries>
#include <QtCharts>

using namespace QtCharts;

QtChartApplicatin::QtChartApplicatin(QWidget *parent) : QMainWindow(parent) {
  ui.setupUi(this);

  /* 绘制前时间 */
  QTime startTime = QTime::currentTime();

  /* 绘制图表 */
  QChart *chart = new QChart();

  /* 设置自定义坐标轴 */
  QValueAxis *axisX = new QValueAxis(); /* X轴 */
  QValueAxis *axisY = new QValueAxis(); /* Y轴 */

  /* 设置坐标轴范围 */
  axisX->setRange(0, 24);
  axisY->setRange(0, 2);

  /* 设置坐标轴刻度线(可以设置主要和次要刻度线) 可以按固定值(配合间隔)、份设置刻度线 */
  axisX->setTickType(QValueAxis::TickType::TicksFixed);
  axisX->setTickCount(7);
  axisY->setTickType(QValueAxis::TickType::TicksDynamic);
  axisY->setTickInterval(0.4);

  /* 设置刻度线颜色 */
  axisY->setGridLineColor(QColor("#D9D9D9"));
  axisX->setLinePenColor(QColor("#666666"));

  /* 隐藏Y轴和X轴刻度线 */
  axisX->setGridLineVisible(false);
  axisY->setLineVisible(false);

  /* QSplineSeries 平滑曲线  QLineSeries折线 */
  QLineSeries *LineSeries1 = new QLineSeries();
  QLineSeries *LineSeries2 = new QLineSeries();

  /* 添加数据 */
  for (double x = 0; x < 24; x += 1) {
      LineSeries1->append(x, sin(x));
      LineSeries2->append(x, cos(x));
  }

  /* 绘制数据点与线 */
  LineSeries1->setPointsVisible(true);
  LineSeries2->setPointsVisible(true);

  LineSeries1->setPen(QPen(QColor("#24B354"), 2, Qt::SolidLine));
  LineSeries2->setPen(QPen(QColor("#1786E6"), 2, Qt::SolidLine));

  /* 图例 */
  LineSeries1->setName("consumption");
  LineSeries2->setName("generation");
  chart->legend()->hide();

  /* 将坐标轴绑定图表 */
  chart->setAxisX(axisX, LineSeries1);
  chart->setAxisY(axisY, LineSeries1);

  /* 将系列绑定图表 */
  chart->addSeries(LineSeries1);
  chart->addSeries(LineSeries2);

  /* 去锯齿 试线条显示更简洁美观 */
  ui.widget->setRenderHint(QPainter::RenderHint::Antialiasing);

  /* 将图表设置到控件(chartview)内 */
  ui.widget->setChart(chart);

  QTime endTime = QTime::currentTime();
  auto totalTime = startTime.msecsTo(endTime);
}
 ```
{F2291162}
<2>使用qcustomplot绘制
Qcustomplot类管理着所有的图层,默认自带了六个图层,分别是:
 背景层background
 网格层grid
 绘图层main
 坐标轴层axes
 图例层legend
 overlay层overlay(交互层)
各层按顺序绘制,其中前五个图层共享一个绘图缓存,overlay为单独绘制机制,可以对overlay图层进行单独的更新,减少刷新时间。
```
lang=C,
#include "QtCustomPlotApplication1.h"
#include "qcustomplot.h"

QtCustomPlotApplication1::QtCustomPlotApplication1(QWidget *parent)
    : QMainWindow(parent) {
  ui.setupUi(this);

/* 连接鼠标事件  */
  connect(ui.customPlot, SIGNAL(mouseMove(QMouseEvent *)), this,
          SLOT(mouseMove(QMouseEvent *)));

  /* 生成数据,画出的是抛物线 */
  QVector<double> x, y0, y1;
  for (double i = 0; i < 24; i += 0.1) {
    x.append(i);
    y0.append(1 + sin(i));
    y1.append(1 + cos(i));
  }

  /* 添加数据曲线(一个图像可以有多个数据曲线) */
  ui.customPlot->addGraph();

  /* 一个曲线对应一个graph, 每添加一条曲线可以通过addgraph添加
   * 可以将每一条曲线理解为一个图层
   * qcustomplot一共有四个坐标轴,xAxis/xAxis2/yAxis/yAxis2
   */
  ui.customPlot->addGraph();
  /* 边框右侧和上侧均显示刻度线,但不显示刻度值 */
  ui.customPlot->xAxis2->setVisible(false);
  ui.customPlot->xAxis2->setTickLabels(false);
  ui.customPlot->yAxis2->setVisible(false);
  ui.customPlot->yAxis2->setTickLabels(false);

  /* graph(0);可以获取某个数据曲线(按添加先后排序) */
  /* setData();为数据曲线关联数据 */
  ui.customPlot->graph(0)->setData(x, y0);
  ui.customPlot->graph(0)->setName("consumption");

  ui.customPlot->graph(1)->setData(x, y1);
  ui.customPlot->graph(1)->setName("generation");

  /* 设置曲线颜色 */
  ui.customPlot->graph(0)->setPen(QPen(QBrush(QColor("#24B354")), 2));
  ui.customPlot->graph(1)->setPen(QPen(QBrush(QColor("#1786E6")), 2));
  ui.customPlot->graph(0)->setScatterStyle(
      QCPScatterStyle(QCPScatterStyle::ssDisc, 5)); //设置散点形状
  ui.customPlot->graph(1)->setScatterStyle(
      QCPScatterStyle(QCPScatterStyle::ssDisc, 5)); //设置散点形状

  /* 线段风格 */
  // ui.customPlot->graph(0)->setLineStyle(QCPGraph::LineStyle::lsLine);

  /* 为坐标轴添加标签 */
  //ui.customPlot->xAxis->setLabel("x");
  //ui.customPlot->yAxis->setLabel("y");

  /* 设置X轴不显示刻度以及网格 */
  ui.customPlot->xAxis->setTicker(false);
  ui.customPlot->xAxis->setSubTicks(false);
  ui.customPlot->xAxis->grid()->setVisible(false);
  ui.customPlot->xAxis->setBasePen(QPen(QColor("#666666"), 1));//设置下轴颜色

  /* 设置Y轴仅显示网格线 */
  ui.customPlot->yAxis->setBasePen(QPen(QColor(0,0,0,0), 1));//隐藏左轴
  ui.customPlot->yAxis->setTickLength(0);
  ui.customPlot->yAxis->setSubTicks(false);
  ui.customPlot->yAxis->grid()->setPen(QPen(QColor("#D9D9D9"), 1));

  /*设置坐标轴的范围,以看到所有数据 */
  ui.customPlot->xAxis->setRange(0, 25);
  ui.customPlot->xAxis->ticker()->setTickStepStrategy(QCPAxisTicker::tssMeetTickCount);
  ui.customPlot->xAxis->ticker()->setTickCount(6);

  ui.customPlot->yAxis->setRange(0, 2);
  ui.customPlot->legend->setVisible(false);

  /* 支持鼠标拖拽轴的范围、滚动缩放轴的范围,左键点选图层(每条曲线独占一个图层)
   */
  ui.customPlot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom |
                                 QCP::iSelectPlottables);

  /* 生成游标 */
  tracer_ = new QCPItemTracer(ui.customPlot);

  tracer_->setPen(QPen(Qt::red));             //圆圈轮廓颜色
  tracer_->setBrush(QBrush(Qt::red));         //圆圈圈内颜色
  tracer_->setStyle(QCPItemTracer::tsCircle); //圆圈
  tracer_->setSize(5);                        //设置大小

  /* 生成游标说明 */
  tracerLabel_ = new QCPItemText(ui.customPlot);
  tracerLabel_->setLayer("overlay"); //设置图层为overlay,因为需要频繁刷新
  tracerLabel_->setPen(QPen(Qt::black)); //设置游标说明颜色
  tracerLabel_->setPositionAlignment(Qt::AlignLeft | Qt::AlignTop); //设置位置
  tracerLabel_->position->setParentAnchor(
      tracer_->position); //将游标说明锚固在tracer位置处,实现自动跟随
  tracerLabel_->setVisible(false);

  /* 重画图像 */
  ui.customPlot->replot();
}

void QtCustomPlotApplication1::mouseMove(QMouseEvent *e) {
  QCPGraph *mGraph = ui.customPlot->graph(0);
  //将像素点转换成qcustomplot中的坐标值,并通过setGraphKey将锚点值设为真实数据值。tracer->setGraphKey(xAxis->pixelToCoord(event->pos().x()));
  int graphCount = ui.customPlot->graphCount();
  /* 获得鼠标位置处对应的横坐标数据x */
  double x = ui.customPlot->xAxis->pixelToCoord(e->pos().x());
  /* 遍历曲线 */
  for (int i = 0; i < graphCount; ++i) {
    /* 判断哪一条曲线被选中 */
    if (ui.customPlot->graph(i)->selected()) {
      /* 显示锚点 */
      tracer_->setVisible(true);
      mGraph = ui.customPlot->graph(i);

      tracer_->setGraph(mGraph); //将锚点设置到被选中的曲线上
      tracer_->setGraphKey(x); //将游标横坐标设置成刚获得的横坐标数据x
      tracer_->setInterpolating(
          true); //游标的纵坐标可以通过曲线数据线性插值自动获得
      tracer_->updatePosition(); //使得刚设置游标的横纵坐标位置生效
      double xValue = tracer_->position->key();
      double yValue = tracer_->position->value();
      /* 显示游标说明框 */
      tracerLabel_->setText(QString("%1: x = %2, y = %3")
                                .arg(mGraph->name())
                                .arg(QString::number(xValue))
                                .arg(QString::number(yValue)));
      break;
    } else {
      /* 没有曲线被选中,不显示锚点 */
      tracer_->setVisible(false);
    }
  }
  /* 重绘 */
  ui.customPlot->layout(5)->replot();
}
```
 {F2291163}
其中QCharts(QDateTimeAxis)和Qcustomplot(QCPAxisTickerDateTime)都支持日期格式的坐标轴  ,均是通过时间戳与日期之间的转换,使得坐标轴以日期、时间的格式显示。还可以设置对数、科学计数等显示方式。

QChart和QCustomPlot都可以通过重写鼠标事件实现与数据图表的交互,但是Qcustomplot可以通过设置setInteractions() 直接实现缩放、放大、拖动等简单的交互,并且提供了QCPItemTracer、QCPItemText简单控件实现数据显示等功能。
 {F2291171}

=五、 绘图效率与质量=
表中是测试时长为代码中加载完成图表所需时间,在将图表设置到UI端的view控件内的时间未计算。
|数据点/耗时(ms)|    QCharts|    Qcustomplot    |Qpaint|
|24    |240    |201|    4|
|240    |268    |207    |17|
|2400|    388    |221|    102|
|24000    |1631(开始卡顿)|    254|    974|
|240000|    14009(UI加载不出来)|    368    |9596|
|2400000    |144949    |1829(略微卡顿)|    93144|
|源代码行数    |78|    145    |558|
QCharts:
 {F2291165}
QCustomplot:
 {F2291166}
   
=六、 总结=
当数据量较小时:QPaint > QCustomPlot > QChart
当数据量较大时:QCustomPlot > QPaint > QChart
图表美观度:QCustomPlot > QChart
交互功能:QCustomPlot > QChart
因此如果绘制比较简单的图形或内容和常见图表差异较大的情况可以使用paint直接绘制,如果绘制常见的图表,并且具有一定数据量的情况下,可以优先考虑使用qcustomplot。
 

  • 23
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C知道: 嗨!关于QCustomPlot的基本使用,我可以给你一些指导。 首先,你需要确保已经正确安装了QCustomPlot库。你可以从官方网站(https://www.qcustomplot.com/)下载最新版本的库,并按照文档中的说明进行安装。 一旦你已经安装好了库,你可以在你的项目中包含QCustomPlot头文件,并链接QCustomPlot库。 下面是一个简单的示例,展示了如何使用QCustomPlot绘制一个简单的曲线图: ```cpp #include <QApplication> #include <QCustomPlot> int main(int argc, char *argv[]) { QApplication a(argc, argv); // 创建一个QCustomPlot对象 QCustomPlot plot; // 创建一些数据点 QVector<double> xData, yData; for (int i = 0; i < 100; ++i) { xData.push_back(i); yData.push_back(qSin(i / 10.0)); } // 创建一个曲线图层,并设置数据 QCPGraph *graph = plot.addGraph(); graph->setData(xData, yData); // 设置图表标题和轴标签 plot.plotLayout()->insertRow(0); plot.plotLayout()->addElement(0, 0, new QCPTextElement(&plot, "曲线图", QFont("sans", 12, QFont::Bold))); plot.xAxis->setLabel("X轴"); plot.yAxis->setLabel("Y轴"); // 设置曲线的颜色和样式 graph->setPen(QPen(Qt::blue)); graph->setLineStyle(QCPGraph::lsLine); // 设置图表的范围 plot.xAxis->setRange(0, 100); plot.yAxis->setRange(-1, 1); // 显示图表窗口 plot.show(); return a.exec(); } ``` 这个示例中,我们首先创建了一个QCustomPlot对象,然后生成一些数据点,并将它们设置给一个QCPGraph对象。然后,我们设置了图表的标题、轴标签、曲线的颜色和样式,以及图表的范围。最后,我们显示了图表窗口。 你可以根据自己的需要修改代码,添加更多的曲线、图表元素和样式,来实现更复杂的图表展示。 希望这些信息能对你有所帮助!如果你有任何问题,都可以继续问我哦。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值