本文假定你会使用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_OBJECT
public:
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 0
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();
#else
ui.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++;
}