这片文章是之前文章思路上来的,之前的这篇文章是在项目初期,刚开始使用QtCharts时候写的,当时比较匆忙,没有太多时间编写一个Demo,代码也是从项目中抠出来的,难免会有不足之处,现在看起来有点晦涩,可能对大家的帮助不大,所以想进行一定修改,让大家能够更好的使用Qt自带的折线图,实现更多功能。
本来是想在之前的文章上进行修改,但是毕竟也是以前的一个印记。这次就在上那篇文章的基础上,试图让整个流程更加清楚,增加一些新内容,也会配上Demo的下载地址。
另外,本Demo的开发环境是VS2017社区版+Qt 5.11.2,QtChart的添加方式和使用Qt Creator略有不同。(本人觉得开发大一点的项目还是VS方便,所以就一直使用的VS进行开发)
QtCharts常用的时间轴有QValueAxis和QDateTimeAxis,有时候我们需要绘制与时间相关的数据,如与日期相关的天气数据,或者是随分钟变化的传感器数据等,这样就会用到 QDateTimeAxis 坐标轴目前网上的一些例子,以及QT自带的例子,基本都是和日期相关的数据,没有找到坐标轴是分钟、秒的案例,踩了一些坑后,写下这篇文章,希望能够帮助到需要的人。
记得在生成项目的时候勾选charts(安装Qt的时候记得也要安装这个组件),这样就能正常使用QtCharts,一路next就可以生成我们的项目了。
我们要实现折线图需要利用QChartView,在QChartView中才可以添加QChart。
双击ui文件打开QtDesigner,我们会发现没有现成的QChartView控件。但是问题不大,QChartView是继承于GraphicsView的,所以我们可以通过Qt的一些操作,将GraphicsView变为我们要使用的QChartView。
首先我们拖动一个GraphicsView到右边去,对着添加进去的控件右键,选择提升,然后在弹出窗口,进行下面的操作,确定后我们就可以得到一个QChartView了。
可以看到,右边属性界面我们的graphicsView的类就变为了QChartView
这个时候我们进行编译,是会报错的,大概就是下面这个样子
需要在头文件中添加一个包含,就可以正常使用了
主要是初始化坐标轴和数据集,以及QChart对象。(我们这里既有左边的Y轴,又有右边的Y轴,如果只是想显示普通一条数据,只需要一个Y轴就可以了)
m_AxisX_Time = new QDateTimeAxis();//时间轴
m_AxisY_Left = new QValueAxis();//左边Y轴
m_AxisY_Right = new QValueAxis();//右边Y轴
m_LeftSeries = new QLineSeries();//折线图数据集
m_RightSeries = new QLineSeries();
m_LineChart = new QChart();//chart对象
其中这个m_LineChart是要添加到我们QChartView中的具体对象,也是折线图的具体对象。
有了这些对象,我们需要对他们之间进行初始设置,添加他们之间的关系,让他们能够各司其职,共同工作。
首先就是把我们的数据集加入到我们的chart中
//添加曲线到chart中
m_LineChart->addSeries(m_LeftSeries);
m_LineChart->addSeries(m_RightSeries);
然后我们对坐标轴进行一定的设置。时间轴设置区间需要用到QDateTime,QDateTime是一个年月日,时分秒的时间类,构造函数是由年月日的m_BaseData对象(QDate类)和m_BaseTime对象(QTime类)组成,但是因为我们想要显示时分秒或者分秒,所以调用下面一句话,我们可以只是显示分秒。
m_AxisX_Time->setFormat(“mm:ss”)
具体的代码如下
QDateTime temp_StartTime(m_BaseDate, m_BaseTime);//00:00
QDateTime temp_EndTime(m_BaseDate, m_EndTime);//02:00
m_AxisX_Time->setTickCount(6);//分为六格
m_AxisX_Time->setRange(temp_StartTime, temp_EndTime);//时间显示范围
//坐标轴显示方式: 分钟:秒
m_AxisX_Time->setFormat("mm:ss");
//设置坐标轴显示范围
m_AxisY_Left->setRange(-900, 2000);
m_AxisY_Right->setRange(-900, 1500);
- 这里有一个坑,QDateTime中,如果初始化输入QDate和QTime时间不正确,那么理论上QDateTime也是错误的,但是系统是不会报错的,但会导致显示数据异常;
- 比如QDate如果是(2000,0,1),不会提示错误,但是其实显示的数值会一直是错误的
- 所以为了保证数据的正确性,这些容易出错的对象我们尽量用全局的const变量来提前定义,如m_BaseDate。
然后我们把设置好的坐标添加到chart中,和添加进数据集的方法相似
//把坐标轴添加到chart中,
//addAxis函数的第二个参数是设置坐标轴的位置,
//只有四个选项,下方:Qt::AlignBottom,左边:Qt::AlignLeft,右边:Qt::AlignRight,上方:Qt::AlignTop
m_LineChart->addAxis(m_AxisX_Time, Qt::AlignBottom);
m_LineChart->addAxis(m_AxisY_Left, Qt::AlignLeft);
m_LineChart->addAxis(m_AxisY_Right, Qt::AlignRight);
最后将数据集和坐标轴绑定。每个数据集都需要绑定X轴-时间轴和对应的Y轴,如果想要添加多条折线图,原理也是一样的,只需要绑定X轴和对应的Y轴就可以了。
//把曲线关联到坐标轴
m_LeftSeries->attachAxis(m_AxisX_Time);
m_LeftSeries->attachAxis(m_AxisY_Left);
m_RightSeries->attachAxis(m_AxisX_Time);
m_RightSeries->attachAxis(m_AxisY_Right);
到这里,我们的chart就设置完毕了,我们将设置好的chart添加进我们的chartView中就可以了
ui.graphicsView->setChart(m_LineChart);
想要往QtChart中添加数据,只需要往对应的数据集series中添加点,为了方便调用,这里写成了一个函数形式。
/**
* 添添加一个点
* */
void QtChartTimeAxis::addOnePointToChart(QLineSeries *targetSeries, int secondCount, int y_value)
{
QDateTime temp_AddTimePos(m_BaseDate, m_BaseTime.addSecs(secondCount));//通过addSecs增加秒数,更加安全
targetSeries->append(temp_AddTimePos.toMSecsSinceEpoch(), y_value);
}
我们这里通过定时器,每一秒钟绘制一次数据点,这和我们期望的实际的工作方式是一致。
//初始化一个定时器
m_DrawTimer = new QTimer(this);
connect(m_DrawTimer, &QTimer::timeout, this, &QtChartTimeAxis::oneSecondAction);//槽函数,每次定时器达到指定时间就执行一次
开始定时器只需要执行下面这一行,括号内这个间隔单位是ms,可以按照自己的要求进行更改。
m_DrawTimer->start(1000);//1秒执行一次
然后在每秒响应的槽函数中,每一秒调用一次addOnePointToChart函数,
second_count++;
addOnePointToChart(m_LeftSeries, second_count, m_DataList[second_count].toInt());
可以设置左右Y轴的颜色,名称,以及让曲线颜色和Y轴颜色一致。因为不是非常重要,就放在了最后
/**
* 设置坐标轴样式
* */
void QtChartTimeAxis::setAxisFormat(QValueAxis *axis, QXYSeries *lineSeries, QString titleString, QColor color)
{
axis->setTitleText(titleString);
axis->setTitleFont(QFont("黑体", 8, QFont::Medium, false));
axis->setTitleBrush(color);
axis->setLinePenColor(color);
lineSeries->setPen(QPen(color, 0.6, Qt::SolidLine, Qt::SquareCap, Qt::RoundJoin));}
同样的,因为不是非常重要,就放在了最后。但是有时候可能会对边距有要求。
/** * 用于设置折线图边距 */
void QtChartTimeAxis::setLineChartMargins(QChart *chart, int margin)
{
QMargins m_Margin;
m_Margin.setLeft(margin);
m_Margin.setBottom(margin);
m_Margin.setRight(margin);
m_Margin.setTop(margin);
chart->setMargins(m_Margin);
}
下载 程序及数据下载连接
说明:程序提供的下载(本程序是利用VS2017+Qt 5.11.2进行编写,建议用相同环境打开)
QtChart还是适合轻量级的应用,比如这个Demo是1s绘制一次,所以性能上没有一点问题,100ms也不会有什么问题,但是10ms的绘制间隙后,系统明显会卡顿了,这对系统执行的其他任务影响很大,这个时候就需要自定义的绘制模块了。