本文假定你会使用Qt开发,但未接触过QCustomPlot绘图类或者是刚接触。
如何往Qt中引入QCustomPlot
- 首先,去官网下载最新版本的源码,注意是
QCustomPlot.tar.gz
这个文件,里面包含源码和示例。实际上,我们只需要qcustomplot.h
和qcustomplot.h
这两个源文件。
- 将代码文件拷贝到本地工程,并引入。
QCustomPlot需要依赖printsupport
模块,如果你是使用QT+VS开发,配置如下:
如果是Qt Create
开发,在.pro
文件中添加:QT += QWidget printsupport
。 - 在Qt中新建ui文件,拖拽一个
QWidget
控件,将其提升为QCustomPlot
。
QCustomPlot常用函数
// 设置背景色
ui.plotWidget->setBackground(QBrush(QColor("#404040")));// 设置X/Y轴的标签
ui.plotWidget->xAxis->setLabel(QStringLiteral("次数"));// 设置X/Y轴标签字体
ui.plotWidget->xAxis->setLabelFont(plotFont);// 设置X/Y轴标签颜色
ui.plotWidget->xAxis->setLabelColor(QColor(Qt::red));// 设置x=0或y=0所在直线的画笔
ui.plotWidget->xAxis->grid()->setZeroLinePen(QPen(QColor(Qt::yellow)));// 设置X/Y轴刻度范围
ui.plotWidget->xAxis->setRange(1, PT_CNT);// 设置X/Y轴刻度数,也就是分为几段
ui.plotWidget->xAxis->ticker()->setTickCount(8);// 设置X/Y轴刻度值文本的颜色
ui.plotWidget->xAxis->setTickLabelColor(QColor(Qt::green));// 设置X/Y轴轴线的画笔
ui.plotWidget->xAxis->setBasePen(QPen(QColor(Qt::white), 2, Qt::SolidLine));// 设置X/Y轴大刻度的画笔,被分段的位置
ui.plotWidget->xAxis->setTickPen(QPen(QColor("#ff00ff")));// 设置X/Y轴小刻度的画笔
ui.plotWidget->xAxis->setSubTickPen(QPen(QColor("#00ffff")));// 设置内部网格线的画笔
ui.plotWidget->xAxis->grid()->setPen(QPen(QColor(Qt::darkRed), 1, Qt::DotLine));// 添加一个图层
ui.plotWidget->addGraph();// 为对应图层添加数据
ui.plotWidget->graph(0)->addData(keys, values);// 为图层设置画笔
ui.plotWidget->graph(0)->setPen(QColor(Qt::blue));// 设置是/否抗锯齿
ui.plotWidget->graph(0)->setAntialiasedFill(true);// 刷新绘图,更改数据后需手动刷新(缩放会自动刷新)
ui.plotWidget->replot();// 支持拖拽和缩放
ui.plotWidget->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom);
绘制直方图
更改QCustomPlot
相关属性,这里以颜色修改为主(稍有点乱哈),创建距离-测距次数
的直方图。
相关代码如下:
void PlotTest::InitForm()
{ui.plotWidget->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom);ui.plotWidget->setBackground(QBrush(QColor("#404040")));ui.plotWidget->xAxis->setLabel(QStringLiteral("次数"));ui.plotWidget->yAxis->setLabel(QStringLiteral("距离(cm)"));QFont plotFont = font();plotFont.setPointSizeF(10.0);ui.plotWidget->xAxis->setLabelFont(plotFont);ui.plotWidget->yAxis->setLabelFont(plotFont);ui.plotWidget->xAxis->setLabelColor(QColor(Qt::red));ui.plotWidget->yAxis->setLabelColor(QColor(Qt::red));ui.plotWidget->xAxis->grid()->setZeroLinePen(QPen(QColor(Qt::yellow)));ui.plotWidget->yAxis->grid()->setZeroLinePen(QPen(QColor(Qt::yellow)));ui.plotWidget->xAxis->setRange(1, PT_CNT);ui.plotWidget->yAxis->setRange(-10, 90);ui.plotWidget->xAxis->ticker()->setTickCount(8);ui.plotWidget->yAxis->ticker()->setTickCount(8);ui.plotWidget->xAxis->setTickLabelColor(QColor(Qt::green));ui.plotWidget->yAxis->setTickLabelColor(QColor(Qt::green));ui.plotWidget->xAxis->setBasePen(QPen(QColor(Qt::white), 2, Qt::SolidLine));ui.plotWidget->yAxis->setBasePen(QPen(QColor(Qt::white), 2, Qt::SolidLine));ui.plotWidget->xAxis->setTickPen(QPen(QColor("#ff00ff")));ui.plotWidget->yAxis->setTickPen(QPen(QColor("#ff00ff")));ui.plotWidget->xAxis->setSubTickPen(QPen(QColor("#00ffff")));ui.plotWidget->yAxis->setSubTickPen(QPen(QColor("#00ffff")));ui.plotWidget->xAxis->grid()->setPen(QPen(QColor(Qt::darkRed), 1, Qt::DotLine));ui.plotWidget->yAxis->grid()->setPen(QPen(QColor(Qt::darkGreen), 1, Qt::DotLine));QVector<double> keys, values;for (int i = 1; i <= PT_CNT; i++){keys.push_back(i);values.push_back(rand() % 100 - 10);}ui.plotWidget->addGraph();ui.plotWidget->graph(0)->addData(keys, values);ui.plotWidget->graph(0)->setPen(QColor(Qt::blue));ui.plotWidget->graph(0)->setAntialiasedFill(true);ui.plotWidget->replot();
}
刷新直方图
刷新直方图比较简单,刷新指定图层的数据即可。有2种方式:
- 更换数据
ui.plotWidget->graph(0)->data()->clear(); // 清楚图层对应的数据
ui.plotWidget->graph(0)->addData(keys, values); // 添加新的数据
- 更换图层
ui.plotWidget->clearGraphs(); // 删除图层(单个或所有)
ui.plotWidget->addGraph(); // 新建图层
ui.plotWidget->graph(0)->addData(keys, values); // 添加新数据
注:两种方式会适用于不同的场景下。
绘制连续的直方图
连续直方图可以理解为:不断往图层里添加数据。需要注意的是,每次添加数据都需要更新刻度范围。代码如下:
void PlotTest::DrawContinueGraph()
{QVector<double> keys, values;for (int i = 1; i <= PT_CNT; i++){keys.push_back(mRefreshCnt * PT_CNT + i);values.push_back(rand() % 100 + 1);}ui.plotWidget->graph(0)->addData(keys, values);ui.plotWidget->xAxis->setRange(1, PT_CNT * (mRefreshCnt + 1));ui.plotWidget->graph(0)->setAntialiasedFill(true);ui.plotWidget->replot();mRefreshCnt++;
}
完整代码
// PlotTest.h文件
#pragma once#include <QtWidgets/QWidget>
#include "ui_PlotTest.h"class PlotTest : public QWidget
{Q_OBJECTpublic:PlotTest(QWidget *parent = nullptr);~PlotTest();public:void InitForm(); // 初始化控件void DrawStaticGraph(); // 绘制静态库void DrawDynamicGraph(); // 绘制动态库(单图刷新)void DrawContinueGraph(); // 绘制连续图(多图刷新)public slots:void on_btnDynamicDraw_clicked();void on_btnContinueDraw_clicked();private:Ui::PlotTestClass ui;int mRefreshCnt; // 连续刷新次数
};
// PlotTest.cpp文件
#include "PlotTest.h"
#include "CustomPlot\qcustomplot.h"#define PT_CNT 200 // 点数
#define GRAPH_CNT 5 // 图数PlotTest::PlotTest(QWidget *parent): QWidget(parent)
{ui.setupUi(this);InitForm();mRefreshCnt = 1;
}PlotTest::~PlotTest()
{}void PlotTest::on_btnDynamicDraw_clicked()
{ui.btnDynamicDraw->setEnabled(false);ui.btnContinueDraw->setEnabled(false);mRefreshCnt = 1;for (int i = 0; i < 10; i++){DrawDynamicGraph();Sleep(500);}ui.btnDynamicDraw->setEnabled(true);ui.btnContinueDraw->setEnabled(true);
}void PlotTest::on_btnContinueDraw_clicked()
{ui.btnDynamicDraw->setEnabled(false);ui.btnContinueDraw->setEnabled(false);mRefreshCnt = 0;ui.plotWidget->graph(0)->data()->clear();ui.plotWidget->xAxis->setRange(1, PT_CNT);for (int i = 0; i < 10; i++){DrawContinueGraph();Sleep(500);}ui.btnDynamicDraw->setEnabled(true);ui.btnContinueDraw->setEnabled(true);
}void PlotTest::InitForm()
{ui.plotWidget->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom);#if 0ui.plotWidget->setBackground(QBrush(QColor("#404040")));ui.plotWidget->xAxis->setLabel(QStringLiteral("次数"));ui.plotWidget->yAxis->setLabel(QStringLiteral("距离(cm)"));QFont plotFont = font();plotFont.setPointSizeF(10.0);ui.plotWidget->xAxis->setLabelFont(plotFont);ui.plotWidget->yAxis->setLabelFont(plotFont);ui.plotWidget->xAxis->setLabelColor(QColor(Qt::red));ui.plotWidget->yAxis->setLabelColor(QColor(Qt::red));ui.plotWidget->xAxis->grid()->setZeroLinePen(QPen(QColor(Qt::yellow)));ui.plotWidget->yAxis->grid()->setZeroLinePen(QPen(QColor(Qt::yellow)));ui.plotWidget->xAxis->setRange(1, PT_CNT);ui.plotWidget->yAxis->setRange(-10, 90);ui.plotWidget->xAxis->ticker()->setTickCount(8);ui.plotWidget->yAxis->ticker()->setTickCount(8);ui.plotWidget->xAxis->setTickLabelColor(QColor(Qt::green));ui.plotWidget->yAxis->setTickLabelColor(QColor(Qt::green));ui.plotWidget->xAxis->setBasePen(QPen(QColor(Qt::white), 2, Qt::SolidLine));ui.plotWidget->yAxis->setBasePen(QPen(QColor(Qt::white), 2, Qt::SolidLine));ui.plotWidget->xAxis->setTickPen(QPen(QColor("#ff00ff")));ui.plotWidget->yAxis->setTickPen(QPen(QColor("#ff00ff")));ui.plotWidget->xAxis->setSubTickPen(QPen(QColor("#00ffff")));ui.plotWidget->yAxis->setSubTickPen(QPen(QColor("#00ffff")));ui.plotWidget->xAxis->grid()->setPen(QPen(QColor(Qt::darkRed), 1, Qt::DotLine));ui.plotWidget->yAxis->grid()->setPen(QPen(QColor(Qt::darkGreen), 1, Qt::DotLine));QVector<double> keys, values;for (int i = 1; i <= PT_CNT; i++){keys.push_back(i);values.push_back(rand() % 100 - 10);}ui.plotWidget->addGraph();ui.plotWidget->graph(0)->addData(keys, values);ui.plotWidget->graph(0)->setPen(QColor(Qt::blue));ui.plotWidget->graph(0)->setAntialiasedFill(true);ui.plotWidget->replot();
#elseui.plotWidget->xAxis->setLabel(QStringLiteral("次数"));ui.plotWidget->yAxis->setLabel(QStringLiteral("距离(cm)"));ui.plotWidget->xAxis->setRange(1, PT_CNT);ui.plotWidget->yAxis->setRange(1, 100);ui.plotWidget->xAxis->ticker()->setTickCount(8);ui.plotWidget->yAxis->ticker()->setTickCount(8);DrawStaticGraph();#endif
}void PlotTest::DrawStaticGraph()
{QVector<double> keys, values;for (int i = 1; i <= PT_CNT; i++){keys.push_back(i);values.push_back(rand() % 100 + 1);}ui.plotWidget->addGraph();ui.plotWidget->graph(0)->addData(keys, values);ui.plotWidget->graph(0)->setPen(QColor(Qt::blue));ui.plotWidget->graph(0)->setAntialiasedFill(true);ui.plotWidget->replot();
}void PlotTest::DrawDynamicGraph()
{ui.plotWidget->clearGraphs();QVector<double> keys, values;for (int i = 1; i <= PT_CNT; i++){keys.push_back(i);values.push_back(rand() % 100 + 1);}ui.plotWidget->addGraph();ui.plotWidget->graph(0)->addData(keys, values);ui.plotWidget->xAxis->setRange(1, PT_CNT);ui.plotWidget->graph(0)->setAntialiasedFill(true);ui.plotWidget->replot();
}void PlotTest::DrawContinueGraph()
{QVector<double> keys, values;for (int i = 1; i <= PT_CNT; i++){keys.push_back(mRefreshCnt * PT_CNT + i);values.push_back(rand() % 100 + 1);}ui.plotWidget->graph(0)->addData(keys, values);ui.plotWidget->xAxis->setRange(1, PT_CNT * (mRefreshCnt + 1));ui.plotWidget->graph(0)->setAntialiasedFill(true);ui.plotWidget->replot();mRefreshCnt++;
}