Qt-QCustomPlot

参考链接

https://blog.csdn.net/llq108/article/details/45603047

https://blog.csdn.net/yxy244/article/details/100311112

https://blog.csdn.net/yxy244/category_9295352.html

简述

QCustomPlot是一个基于Qt C++的图形库,用于绘制和数据可视化 - 制作漂亮的2D图 - 曲线图、趋势图、坐标图、柱状图等,并为实时可视化应用程序提供高性能服务。它没有进一步的依赖关系,并有着良好的文档记录。

QCustomPlot可以导出为各种格式,比如:PDF文件和位图(如:PNG、JPG、BMP)。

可在自己的项目中直接使用两个源文件(qcustomplot.h与qcustomplot.cpp),或预先编译成库。

Qt-QCustomPlot_第1张图片

Qt-QCustomPlot_第2张图片

下载、配置和使用

下载

QCustomPlot首页:http://www.qcustomplot.com/

进入QCustomPlot下载页,下载最新的完整包(包含:源码、文档、示例)!

将下载好的安装包进行解压缩,里面包含文档、示例、更改日志、GPL授权、以及最重要的两个文件qcustomplot.h与qcustomplot.cpp。

配置

文档文档

完整的API文档在complete API documentation上面,或者作为完整包的一部分,在解压缩后的目录中可以找到。里面包含一个HTML文档的层次结构和qch帮助文件用于QtCreator/Assistant集成。如果使用QtCreator或Assistant,应考虑使用qch文件,这将极大地提高工作效率!

集成到QtCreator/Assistant

集成qch文件相当简单:

  1. 复制qcustomplot.qch文件到你需要存储的地方(例如:本地QtCreator配置目录)。
  2. 在QtCreator中,选择:工具 -> 选项 -> 帮助 -> 文档,你会看到一个加载文档模块的列表,以及添加/删除模块的按钮。点击”添加…”按钮,选择qcustomplot.qch文件。

这样,我们就添加完成了。可以通过:帮助 -> 索引,来搜索QCustomPlot相关的类或函数。

当你把光标放在任何QCustomPlot相关的类或函数上时,按下F1键,就会有相应的文档项弹出,就像Qt组件一样。

使用

在examples中我们会看到一些自带的示例,可以运行看一下效果。

如果在自己的项目中使用,需要进行以下配置:

首先,在pro中需要添加(由于QCustomPlot中存在导出功能,使用了printsupport模块):

QT += printsupport

然后,将qcustomplot.h与qcustomplot.cpp拷贝到工程目录下,右键 -> 添加现有文件…,将这两个文件添加至工程。

在调用qcustomplot的地方,需要引入:

#include "qcustomplot.h"

创建一个qcustomplot对象。

QCustomPlot *pCustomPlot = new QCustomPlot(this);

QCustomPlot类

几个重要的类

  • QCustomPlot图标类:用于图标的显示和交互
  • QCPLayer图层:管理图层元素(QCPLayerable),所有可显示的对象都是继承自图层元素。
  • QCPAbstractPlottable绘图元素:包含折线图(QCPGraph)、曲线图(QCPCurve)、柱状图(QCPBars)、QCPStatiBox(盒子图)、QCPColorMap(色谱图)、QCPFinancial(金融图)
  • QCPAxisRect坐标轴矩形:一个坐标轴矩形默认包含上下左右四个坐标,但是可以添加多个坐标轴。

QCustomPlot类管理着所有图层,它本身自带6个图层,分别是:

  1. 背景图(background)
  2. 网格层(grid)
  3. 绘图层(main)
  4. 坐标轴层(axis)
  5. 图例层(legend)
  6. overlay层(overlay)

依据层的顺序不同,绘制的顺序也不同,越在底下的层越早绘制,当前层默认为绘图层main。

我们一般操作的都在绘图层,绘图层则在QCPAxisRect中,QCustomPlot类默认包含一个QCPAxisRect。下图中可以看到一个QCPAxisRect一般包含4个轴。

Qt-QCustomPlot_第3张图片

个性化外观

设置QCustomPlot的背景颜色

QLinearGradient plotGradient; 
plotGradient.setStart(0, 0); 
plotGradient.setFinalStop(0, 350); 
plotGradient.setColorAt(0, QColor(80, 80, 80)); 
plotGradient.setColorAt(1, QColor(50, 50, 50)); 
customPlot->setBackground(plotGradient);   // 设置背景颜色

Qt-QCustomPlot_第4张图片

设置QCPAxisRect轴矩阵的背景颜色

QLinearGradient axisRectGradient; 
axisRectGradient.setStart(0, 0); 
axisRectGradient.setFinalStop(0, 350); 
axisRectGradient.setColorAt(0, QColor(80, 80, 80)); 
axisRectGradient.setColorAt(1, QColor(30, 30, 30)); 
/* 设置QCPAxisRect背景颜色 */ 
customPlot->axisRect()->setBackground(axisRectGradient); 

Qt-QCustomPlot_第5张图片

设置QCPGrid网格的风格

/* 每条网格对应一个刻度 */ 
/* 网格线(对应刻度)画笔 */ 
customPlot->xAxis->grid()->setPen(QPen(QColor(140, 140, 140), 1, Qt::DotLine)); 
customPlot->yAxis->grid()->setPen(QPen(QColor(140, 140, 140), 1, Qt::DotLine)); 
/* 子网格线(对应子刻度)画笔 */ 
customPlot->xAxis->grid()->setSubGridPen(QPen(QColor(80, 80, 80), 1, Qt::DotLine)); 
customPlot->yAxis->grid()->setSubGridPen(QPen(QColor(80, 80, 80), 1, Qt::DotLine)); 
/* 显示子网格线 */ 
customPlot->xAxis->grid()->setSubGridVisible(true);   
customPlot->yAxis->grid()->setSubGridVisible(true); 
/* 设置刻度为0时的网格线的画笔 */ 
customPlot->xAxis->grid()->setZeroLinePen(QPen(Qt::red)); 
customPlot->yAxis->grid()->setZeroLinePen(QPen(Qt::red));

Qt-QCustomPlot_第6张图片

图表的风格

QPen pen; 
QStringList lineNames; 
lineNames << "lsNone" << "lsLine" << "lsStepLeft" << "lsStepRight" << "lsStepCenter" << "lsImpulse"; 
for (int i = QCPGraph::lsNone; i <= QCPGraph::lsImpulse; ++i) 
{   
    customPlot->addGraph();   
    pen.setColor(QColor(qSin(i*1+1.2)*80+80, qSin(i*0.3+0)*80+80, qSin(i*0.3+1.5)*80+80));   
    customPlot->graph()->setPen(pen);    
    // 设置图表的画笔   
    customPlot->graph()->setName(lineNames.at(i-QCPGraph::lsNone));   
    customPlot->graph()->setLineStyle((QCPGraph::LineStyle)i); 
    // 设置图表线段的风格   
    customPlot->graph()->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssCircle, 5)); 
    // 设置图表散点图的样式,散点图的样式有很多种,可以自己试试   
    QVector<double> x(15), y(15);   
    for (int j=0; j<15; ++j)   
    {     
        x[j] = j/15.0 * 5*3.14 + 0.01;     
        y[j] = 7*qSin(x[j])/x[j] - (i-QCPGraph::lsNone)*5 + (QCPGraph::lsImpulse)*5 + 2;   
    }   
    customPlot->graph()->setData(x, y);   
    customPlot->graph()->rescaleAxes(true); 
}

Qt-QCustomPlot_第7张图片

图表画刷
/* 第一种:与0刻度线围成区域 */ 
customPlot->addGraph(); 
customPlot->graph(0)->setPen(QPen(Qt::blue)); 
customPlot->graph(0)->setBrush(QBrush(QColor(0, 0, 255, 20))); 
customPlot->addGraph(); 
customPlot->graph(1)->setPen(QPen(Qt::red)); 
/* 第二种方式:与其它图围成区域,使用的是图0的画刷 */ 
customPlot->graph(0)->setChannelFillGraph(customPlot->graph(1));  
/* 将图0与图1围成区域 */

Qt-QCustomPlot_第8张图片

QCPAxis坐标系

Qt-QCustomPlot_第9张图片

Qt-QCustomPlot_第10张图片

QCPAxis有四个成员变量,分别代表四个坐标轴:xAxis(下)、yAxis(左)、xAxis2(上)、yAxis2(右)。

坐标轴

默认只显示左y轴和下边的x轴,调用setVisible(bool)设置轴是否显示。

customplot->yAxis2->setVisible(true);//显示y轴2
customplot->xAxis2->setVisible(true);//显示x轴2

也可以设置一个完整的坐标Box,会直接显示四个轴。

customplot->axisRect()->setupFullAxesBox();//四边安装轴并显示
设置刻度

提供了设置坐标轴刻度、间距、范围等函数

/* 设置坐标轴刻度间距 */ 
setTickStep(double step); 
/* 设置坐标轴刻度表(将坐标轴刻度设置为vec) */ 
setTickVector(const QVector<double> &vec);
/* 一般刻度数量是自动调整的,但也可以手动设置,例如-100到100默认5个主刻度 */
/* 可以设置成11个主刻度,注意有个刻度步进策略,如果默认是tssReadability,
那么customplot有时仍会自动调整,使刻度便于阅读 */
customplot->xAxis->ticker()->setTickCount(11);//11个主刻度
customplot->xAxis->ticker()->setTickStepStrategy(QCPAxisTicker::tssReadability);
//可读性优于设置
设置标签
customPlot->xAxis->setLabel("x"); 
customPlot->yAxis->setLabel("y");
customplot->xAxis->setTickLabels(true);//显示刻度值
customplot->xAxis->setTickLabelSide(QCPAxis::LabelSide::lsInside);//显示在内部
/* 设置标签旋转角度(顺时针) */
customPlot->xAxis->setTickLabelRotation(30);
设置范围
customPlot->xAxis->setRange(-1, 1); 
customPlot->yAxis->setRange(0, 1);
设置画笔
/* 轴线的画笔 */
customPlot->xAxis->setBasePen(QPen(Qt::white, 1));
/* 轴刻度线的画笔 */
customPlot->xAxis->setTickPen(QPen(Qt::white, 1));
/* 轴子刻度线的画笔 */
customPlot->xAxis->setSubTickPen(QPen(Qt::white, 1));
设置label字体颜色
/* 轴刻度文字颜色 */
customPlot->xAxis->setTickLabelColor(Qt::white);
/* 轴标签颜色 */
customPlot->xAxis->setLabelColor(Qt::white);
设置刻度长度
/* 轴线内刻度的长度 */
customPlot->xAxis->setTickLengthIn(3);
/* 轴线外刻度的长度 */
customPlot->xAxis->setTickLengthOut(5);
customplot->xAxis->setSubTickLengthIn(15);//子刻度向内延伸15
customplot->xAxis->setSubTickLengthOut(5);//子刻度向外延伸5
设置坐标轴线形状
/* 设置轴线结束时的风格为 实角三角形但内部有凹陷的形状,setLowerEnding设置轴线开始时的风格 */
customPlot->xAxis->setUpperEnding(QCPLineEnding::esSpikeArrow);
customplot->xAxis->setUpperEnding(QCPLineEnding::esSpikeArrow);//x轴终点箭头图案
customplot->xAxis->setLowerEnding(QCPLineEnding::esDisc);//x轴起点圆点图案
customplot->yAxis->setUpperEnding(QCPLineEnding::esSquare);//y轴终点小方块图案
设置刻度原点

有些需求要修改刻度显示的原点,例如原来是-10,-5,0,5,10,15,设置原点为1后变成-14,-9,-4,1,6,11,代码例子:

customplot->xAxis->setRange(-15,15);
customplot->xAxis->ticker()->setTickOrigin(1);//改变刻度原点为1
设置坐标轴位置

设置离外部和内部各50,代码例子:

customplot->xAxis->setPadding(50);//填充50的空间
customplot->xAxis->setOffset(50);//偏移50
设置上下轴、左右轴范围同步

利用rangeChanged信号传递轴范围QCPRange,范围改变时将xAxis的范围传给xAxis2,yAxis也是,就能实现轴范围同步了。

connect(customPlot->xAxis, SIGNAL(rangeChanged(QCPRange)), customPlot->xAxis2, SLOT(setRange(QCPRange)));
connect(customPlot->yAxis, SIGNAL(rangeChanged(QCPRange)), customPlot->yAxis2, SLOT(setRange(QCPRange)));
设置坐标轴为时间格式
QSharedPointer<QCPAxisTickerDateTime> dateTick(new QCPAxisTickerDateTime);
dateTick->setDateTimeFormat("yyyy-MM-dd hh:mm:ss:zzz");
customPlot->xAxis->setTicker(dateTick);

网格

设置画笔
/* 网格线(对应刻度)画笔 */
customPlot->xAxis->grid()->setPen(QPen(QColor(140, 140, 140), 1, Qt::DotLine));
customPlot->yAxis->grid()->setPen(QPen(QColor(140, 140, 140), 1, Qt::DotLine));
/* 子网格线(对应子刻度)画笔 */
customPlot->xAxis->grid()->setSubGridPen(QPen(QColor(80, 80, 80), 1, Qt::DotLine));
customPlot->yAxis->grid()->setSubGridPen(QPen(QColor(80, 80, 80), 1, Qt::DotLine));
/* 设置刻度为0时的网格线的画笔 */
customPlot->xAxis->grid()->setZeroLinePen(QPen(Qt::red));
customPlot->yAxis->grid()->setZeroLinePen(QPen(Qt::red));
设置子网络线
/* 显示子网格线 */
customPlot->xAxis->grid()->setSubGridVisible(true);
customPlot->yAxis->grid()->setSubGridVisible(true);

背景

设置背景
customplot->axisRect()->setBackground(QBrush(Qt::black));//背景黑色
customplot->axisRect()->setBackground(QPixmap(":/image/background.jpg"));//背景图片
设置背景属性
customplot->axisRect()->setBackgroundScaled(true);//启用背景缩放 
customplot->axisRect()->setBackgroundScaledMode(Qt::AspectRatioMode::IgnoreAspectRatio);//自由缩放

缩放模式类型和效果

Qt-QCustomPlot_第11张图片

其他设置

设置自动调整范围

设置自动调整范围后,可以使全部数据可见。调用rescaleAxes (bool onlyEnlarge = false)函数,将重新调整与此绘图表关联的键和值轴,以显示所有的数据。

onlyEnlarge 默认false,表示范围可以缩小放大,如果为true表示只能放大,而不会缩小范围。

因为如果有多个曲线,第一个曲线调用rescaleAxes ()函数后,整个坐标轴的范围被缩小,曲线正好占满整个区域,但是如果其他曲线再次调用了rescaleAxes ()函数,如果范围缩小就可能导致数据无法显示,所以后面的曲线要设置参数为true,区域不会被缩小。最终能显示所有曲线的数据。

// 让范围自行缩放,使图0完全适合于可见区域:
customPlot->graph(0)->rescaleAxes();
// 图1也是一样自动调整范围,但只是放大或不变范围
customPlot->graph(1)->rescaleAxes(true);
// 图2也是一样自动调整范围,但只是放大或不变范围
customPlot->graph(2)->rescaleAxes(true);
// 图3也是一样自动调整范围,但只是放大或不变范围
customPlot->graph(2)->rescaleAxes(true);
设置坐标轴缩放比例

QCustomPlot模式对坐标系的x轴和y轴都是一起缩放的,用时候用起来不方便,有时候需要单独对x轴或者y轴进行缩放。

方法1:修改缩放比例

QCustomPlot给我们提供了setRangeZoomFactor()函数,设置区域放大因子。这样就可以实现单个轴放大缩小比例。

ui->customPlot->axisRect()->setRangeZoomFactor(1.2,1);//x方向为1.2 y为1 是不改变。

方法2:QCustomPlot自己提供的函数设置

void MainWindow::wheelEvent(QWheelEvent *event)
{    
	static int i=0;     
	i++;    
	if (ui->customPlot->xAxis->selectedParts().testFlag(QCPAxis::spAxis))    
	{      
		qDebug("%d",i);     
		ui->customPlot->axisRect()->setRangeZoom(ui->customPlot->xAxis->orientation());  
		// ui->customPlot->axisRect()->setRangeZoomFactor(1.2,1);//x方向为1.2    
	}    
	else if (ui->customPlot->yAxis->selectedParts().testFlag(QCPAxis::spAxis))    
	{       
		ui->customPlot->axisRect()->setRangeZoom(ui->customPlot->yAxis->orientation());   
		// ui->customPlot->axisRect()->setRangeZoomFactor(1.2,1);//x方向为1.2    
	}    
	else      
		ui->customPlot->axisRect()->setRangeZoom(Qt::Horizontal|Qt::Vertical);
}
设置坐标系的操作属性
//设置基本坐标轴(左侧Y轴和下方X轴)可拖动、可缩放、曲线可选、legend可选、设置伸缩比例,使所有图例可见
CustomPlot->setInteractions(QCP::iRangeDrag|QCP::iRangeZoom| QCP::iSelectAxes |                                  QCP::iSelectLegend | QCP::iSelectPlottables);

画图类

QCustomPlot 提供了多个画图类

QCPCurve:与QCPGraph 类似,差别在于它是用于展示参数化曲线,可以有循环。

QCPBars:柱形图,如果有多个QCPBars ,可以依次重叠。

QCPStatisticalBox、QCPColorMap、QCPFinancial。与QCPGraph 不同的是,这些画图类在添加到QCustomPlot 的时候需要使用new创建一个实例,而不能直接。

QCPGraph类

添加曲线

每一条曲线相当于一个图层,需要调用qcustomplot来添加。

//向绘图区域QCustomPlot添加一条曲线 
QCPGraph *pGraph = pCustomPlot->addGraph();
给曲线添加数据

添加图层后,可以用qcustomplot的graph(编号)来获取图层对象,或者直接拿到图层指针。编号按照添加的顺序寻址。

customPlot->graph(0)->setData(x, y);
设置图层名称
customPlot->graph(0)->setName("第一个示例");  // 设置曲线图的名字
设置图层(曲线)画笔
QCPGraph::setPen(const QPen &pen);
设置图层(曲线)风格
QCPGraph::setLineStyle(LineStyle ls);
设置曲线形状

曲线形状有“*、+、x、o”等

QCPGraph::setScatterStyle(QCPScatterStyle &style);
设置曲线填充方式

给graph设置brush后,会自动填充曲线和x轴之间的空间。

QCPGraph::setBrush(const QBrush &brush); /* 移除填充  */
QCPGraph::setBrush(Qt::NoBrush);

如果想设置两条曲线之间填充的颜色

/* 设置与某之间曲线填充 */
QCPGraph::setChannelFillGraph(otherGraph);

图例

显示图例

customPlot->legend->setVisible(true);     // 显示图例

添加完数据,记得重画图像

customPlot->replot();
#include "qcustomplot.h" MainWindow::MainWindow(QWidget *parent)   : CustomWindow(parent) 
{       
	...       
	QCustomPlot *pCustomPlot = new QCustomPlot(this);       
	pCustomPlot->resize(300, 300);       // 可变数组存放绘图的坐标的数据,分别存放x和y坐标的数据,101为数据长度       
	QVector<double> x(101), y(101);       // 添加数据,这里演示y = x^3,为了正负对称,x从-10到+10       
	for (int i = 0; i < 101; ++i)       
	{             
		x[i] = i/5 - 10;             
		y[i] = qPow(x[i], 3); // x的y次方;       
	}       
	// 向绘图区域QCustomPlot添加一条曲线      
	QCPGraph *pGraph = pCustomPlot->addGraph();       
	// 添加数据       
	pCustomPlot->graph(0)->setData(x, y);       
	// 设置坐标轴名称       
	pCustomPlot->xAxis->setLabel("x");       
	pCustomPlot->yAxis->setLabel("y");       
	// 设置背景色       
	pCustomPlot->setBackground(QColor(50, 50, 50));       
	pGraph->setPen(QPen(QColor(32, 178, 170)));       
	// 设置x/y轴文本色、轴线色、字体等       
	pCustomPlot->xAxis->setTickLabelColor(Qt::white);       
	pCustomPlot->xAxis->setLabelColor(QColor(0, 160, 230));       
	pCustomPlot->xAxis->setBasePen(QPen(QColor(32, 178, 170)));       
	pCustomPlot->xAxis->setTickPen(QPen(QColor(128, 0, 255)));       
	pCustomPlot->xAxis->setSubTickPen(QColor(255, 165, 0));       
	QFont xFont = pCustomPlot->xAxis->labelFont();       
	xFont.setPixelSize(20);       
	pCustomPlot->xAxis->setLabelFont(xFont);       
	pCustomPlot->yAxis->setTickLabelColor(Qt::white);       
	pCustomPlot->yAxis->setLabelColor(QColor(0, 160, 230));       
	pCustomPlot->yAxis->setBasePen(QPen(QColor(32, 178, 170)));       
	pCustomPlot->yAxis->setTickPen(QPen(QColor(128, 0, 255)));       
	pCustomPlot->yAxis->setSubTickPen(QColor(255, 165, 0));       
	QFont yFont = pCustomPlot->yAxis->labelFont();       
	yFont.setPixelSize(20);       
	pCustomPlot->yAxis->setLabelFont(yFont);       
	// 设置坐标轴显示范围,否则只能看到默认范围       
	pCustomPlot->xAxis->setRange(-11, 11);       
	pCustomPlot->yAxis->setRange(-1100, 1100);       
	...
} 

如果需要导出,我们可以调用对应的save…接口。

例如,导出一张为PNG格式,宽度、宽度分别为400px、300px的图片:

pCustomPlot->savePng("customPlot.png", 400, 300);

QCPGraph

用这个类来添加一个图层

/* 增加图层 */ 
QCPGraph *graphTemp = pCustomPlot->addGraph(); 
/* 设置画笔 */ 
graphTemp->setPen(QPen(Qt::red)); 
/* 设置画刷,曲线和x轴围成的面积颜色 */ 
graphTemp->setBrush(QBrush(QColor(100,0,205,50))); 
graphTemp->setAntialiasedFill(false);    
// 设置图层反锯齿:关闭 
graphTemp->setLineStyle(QCPGraph::lsLine); 
graphTemp->setScatterStyle(QCPScatterStyle::ssDisc);   
// 设置点的形状 
/* 设置图层名称 */ 
graphTemp->setName("实时电流曲线"); 
/* 传入数据,数据类型为double */ 
graphTemp->setData(x, y); 

方案解决

实现横坐标为日期时间

因为曲线轴设置的坐标只能为double型数据,需要将时间转换为double。就需要我们将字符串型的时间数据转换为double型的秒数。需要先将字符串转换为QDateTime,然后再使用totime_t()转换成距离1970年的秒数储存到数组。

你可能感兴趣的:(系统平台开发,qt,开发语言,visual,studio)