Qt学习:QtCharts绘制动态曲线,实时更新数据与坐标轴

1.首先是掌握qtchart的基本使用,封装一个属于自己的绘图类:
Mychart.h

#pragma once
#ifndef CHART_H
#define CHART_H

#include     
#include   //两个基本模块
#include     //点类
#include         //列表
#include    //定时器

QT_CHARTS_BEGIN_NAMESPACE    
class QSplineSeries;
class QValueAxis;                 //引入这两个类而免于引入整个头文件的方法
QT_CHARTS_END_NAMESPACE

QT_CHARTS_USE_NAMESPACE   //使用qtchart需要加入这条语句

//![1]
class Chart : public QChart
{
	Q_OBJECT
public:
	Chart(QGraphicsItem *parent = 0, Qt::WindowFlags wFlags = 0);
	QChartView *m_chartView;   //因为布局时其它函数会访问这个画布,所以设为public
	virtual ~Chart();
	QList setdata();    //预留这个函数作为一个设置图表数据的接口,将外界数据传给图表
public slots:
//	void handleTimeout();
//几个操作数据的槽函数
	void addSeries(QList &data);     //新增一条曲线
	void removeSeries();                            //移出一条曲线
	void connectMarkers();                   //连接图线与图例
	void disconnectMarkers();               //断开图线与图例
	void handleMarkerClicked();           //占击图例时的处理函数
protected:
	void timerEvent(QTimerEvent *event)Q_DECL_OVERRIDE;  //定时器触发事件,重构
private:
	QTimer m_timer;     //定时器指针

	QChart * m_chart;     //图表组件,可理解为画笔,用它画曲线
	QList m_serieslist;   //曲线列表,splineseries为光滑曲线

	QSplineSeries *m_series;     //曲线指针
	QStringList m_titles;             //标题
	QValueAxis *axisX;             //x坐标轴
	QValueAxis *axisY;             //y坐标轴
	
	qreal m_step;                  
	qreal m_x;
	qreal m_y;
};
//![1]

#endif /* CHART_H */

MyChart.cpp

#include "MyChart.h"
#include 
#include 
#include 
#include 
#include 
#include 
#include
#include
#include

int timeId;

Chart::Chart(QGraphicsItem *parent, Qt::WindowFlags wFlags) :QChart(QChart::ChartTypeCartesian, parent, wFlags)
{
	m_chart = new QChart;
	m_chartView = new QChartView(m_chart);
	m_chartView->setRubberBand(QChartView::RectangleRubberBand);  //矩形缩放
	//设置x坐标轴
	axisX = new QValueAxis;
	//axisX->setRange(0, 1000);  //范围
	axisX->setLabelFormat("%d"); //图例的格式  %d为十进制显示
	axisX->setGridLineVisible(true);//网格
	//axisX->setTickCount(11);   //主要刻度
//	axisX->setMinorTickCount(5);//小刻度
	axisX->setTitleText("time/(s)");//标题
//设置y坐标轴
	axisY = new QValueAxis;
	axisY->setRange(0, 20);
	axisY->setLabelFormat("%d");
	axisY->setGridLineVisible(true);
	axisY->setTickCount(10);
	axisY->setMinorTickCount(5);
	axisY->setTitleText("altitude/(%)");

	m_chart->addAxis(axisX, Qt::AlignBottom);  //将坐标轴加到chart上,居下
	m_chart->addAxis(axisY, Qt::AlignLeft);//居左

   //m_chart->setTitle("example of chart");   //设置图表标题
	//m_chart->setAnimationOptions(QChart::SeriesAnimations);  //曲线动画模式,不能启用这一项或是选择这个选项,这个会导致曲线闪烁
	m_chart->legend()->setVisible(true);  //设置图例可见
  //生成一小段数据列表用作绘图初始数据
	QList mydata1;
	for (int i = 0; i <100; i++)
	{
		mydata1.append(QPointF(i, 0.01*i));
	}
	addSeries(mydata1); //增加一条曲线,数据集为mydata1
   connectMarkers();  //将曲线与图例连接起来,可以勾选进行显示与隐藏
   
	m_chart->setAxisX(axisX, m_serieslist.first());  //将x和y坐标轴与第一条曲线连接
	m_chart->setAxisY(axisY, m_serieslist.first());
	timeId = startTimer(500);    //qobject中的函数,设置定时器时间间隔

}

Chart::~Chart()
{

}


void Chart::addSeries(QList &data)  //用于新增曲线
{

	QSplineSeries *series = new QSplineSeries();
	m_serieslist.append(series);//将曲线加到曲线列表中进行管理
	series->setName(QString("line " + QString::number(m_serieslist.count()))); //设置曲线对应的名字,用于图例显示
	series->append(data);  //将数据加到曲线中
	m_chart->addSeries(series);//将曲线增入chart中
	axisX->setRange(0, series->count());  //坐标轴初始范围为图表中的数据数。 这个在绘制多条曲线中需注释

}

void Chart::removeSeries()  //移除一条曲线
{
	// Remove last series from chart
	if (m_serieslist.count() > 0) {
		QSplineSeries *series = m_serieslist.last();
		m_chart->removeSeries(series);
		m_serieslist.removeLast();
		delete series;
	}
}

void Chart::connectMarkers()  //将槽函数与图例的鼠标点击事件连接起来
{
	// Connect all markers to handler
	foreach(QLegendMarker* marker, m_chart->legend()->markers()) {
		// Disconnect possible existing connection to avoid multiple connections
		QObject::disconnect(marker, &QLegendMarker::clicked, this, &Chart::handleMarkerClicked);
		QObject::connect(marker, &QLegendMarker::clicked, this, &Chart::handleMarkerClicked);
	}
}

void Chart::disconnectMarkers()
{
	foreach(QLegendMarker* marker, m_chart->legend()->markers()) {
		QObject::disconnect(marker, &QLegendMarker::clicked, this, &Chart::handleMarkerClicked);
	}
}

void Chart::handleMarkerClicked()//图例点击事件
{
	QLegendMarker* marker = qobject_cast (sender());
	Q_ASSERT(marker);
	//![3]

	//![4]
	switch (marker->type())
		//![4]
	{
	case QLegendMarker::LegendMarkerTypeXY:
	{
		//![5]
		// Toggle visibility of series
		marker->series()->setVisible(!marker->series()->isVisible());

		// Turn legend marker back to visible, since hiding series also hides the marker
		// and we don't want it to happen now.
		marker->setVisible(true);
		//![5]

		//![6]
		// Dim the marker, if series is not visible
		qreal alpha = 1.0;

		if (!marker->series()->isVisible()) {
			alpha = 0.5;
		}

		QColor color;
		QBrush brush = marker->labelBrush();
		color = brush.color();
		color.setAlphaF(alpha);
		brush.setColor(color);
		marker->setLabelBrush(brush);

		brush = marker->brush();
		color = brush.color();
		color.setAlphaF(alpha);
		brush.setColor(color);
		marker->setBrush(brush);

		QPen pen = marker->pen();
		color = pen.color();
		color.setAlphaF(alpha);
		pen.setColor(color);
		marker->setPen(pen);

		//![6]
		break;
	}
	default:
	{
		qDebug() << "Unknown marker type";
		break;
	}
	}
}

QList Chart::setdata()  //设置图表数据的函数接口
{
	QList datalist;
	for (int i = 0; i < 500; i++)
		datalist.append(QPointF(i, i*0.01));
	return datalist;
}

void Chart::timerEvent(QTimerEvent *event)    //定时器事件的重构
{
	if (event->timerId() == timeId)//定时器时间到,模拟数据填充
	{
		static QTime dataTime(QTime::currentTime());
		long int eltime = dataTime.elapsed();  //经过的时间
		static int lastpointtime = 1;
		int size = (eltime - lastpointtime);//数据个数
		qDebug() << "size-->" << size;
		if (isVisible())
		{

			QVectorolddata=m_serieslist.first()->pointsVector();
			olddata.append(QPointF(lastpointtime +olddata.count(), lastpointtime*0.3));//填充数据
			axisX->setRange(0, lastpointtime + m_serieslist.first()->count());//设置x坐标轴
			//后期需更改为一开始固定,只有当数据个数超出坐标轴范围时坐标轴开始扩展。
			m_serieslist.first()->replace(olddata);
			lastpointtime++;
		}
	}
}

关于绘制动态曲线,关键就是在设置好初始画布后进行曲线数据的更新,以及坐标轴的更新。
数据更新可以是定时,也可以新建增加数据的槽函数,当接收到外部数 据时,触发信号进行曲线更新。

坐标轴更新是用于扩展坐标轴以适应曲线。

动态绘制曲线的核心是数据点个数变化,数据个数一定的情况下,是通过进行数据更新通过平移以淘汰最开始的数据。
同时要相应地扩展坐标轴或改变坐标轴。

做上位机界面时,要绘制从下位机收到数据的曲线,需要有一个接收和更新数据的buffer或是datalist。 datalist可方便地去数据头和新增数据。可以作为首选。
收到的数据作为y, (count,data)作为新增的数据点。

你可能感兴趣的:(Qt,Qt,动态曲线,qt上位机绘制曲线)