Qt學習:QtCharts繪製動態曲線,實時更新資料與座標軸
阿新 • • 發佈:2018-12-14
1.首先是掌握qtchart的基本使用,封裝一個屬於自己的繪圖類: Mychart.h
#pragma once #ifndef CHART_H #define CHART_H #include <QtCharts/QChart> #include<QtCharts\QChartView> //兩個基本模組 #include<QPointF> //點類 #include<QList> //列表 #include <QtCore/QTimer> //定時器 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<QPointF> setdata(); //預留這個函式作為一個設定圖表資料的介面,將外界資料傳給圖表 public slots: // void handleTimeout(); //幾個操作資料的槽函式 void addSeries(QList<QPointF> &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<QSplineSeries *> 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 <QtCharts/QAbstractAxis> #include <QtCharts/QSplineSeries> #include <QtCharts/QValueAxis> #include <QtCore/QTime> #include <QtCore/QDebug> #include <QPen> #include<QPainter> #include<QtCharts\QLegendMarker> #include<qmath.h> 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<QPointF> 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<QPointF> &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<QLegendMarker*> (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<QPointF> Chart::setdata() //設定圖表資料的函式介面 { QList<QPointF> 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()) { QVector<QPointF>olddata=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)作為新增的資料點。