qchart折现图_Qt Charts 动态实时折线图绘制
在Qt Charts發布之前,?Qt比較著名兩個畫圖插件是 qwt和Qcustom, 其中Qcustom較輕量,只需要在project 中包含qcustomplot.h 和?qcustomplot.cpp 幾乎就可以使用。
相比Qcustom,qwt功能更為強大,但是它的安裝十分麻煩,阻擋了很多人(包括我)的使用。
但是qwt只是對靜態圖表的表示非常不錯,動態曲線性能并不突出。如果只是靜態繪圖,或者動態繪制的點并不多,繼續用qwt甚至Qcustom完全沒問題。
但是如果是新入手Qt繪圖,用Qt charts顯然是更好的選擇,因為它在各方面都比前兩者要好,并且也易于使用。
并且qml也支持charts,qml的渲染默認用GPU,成長性更好。
如果你在安裝Qt的時候,選擇了Qt charts部分,那么在Qt中使用charts 只需要 在 .pro文件中
QT+=charts
并且在程序的開頭加上一句 using namespace Qtcharts或者一個宏?QT_CHARTS_USE_NAMESPACE
進入主題:?動態實時折線圖繪制
動態繪圖,也就是說折線隨著橫坐標的增長而實時變化。
從這一秒和上一秒的變化看來,就是坐標軸不動,整個圖像往前移了一個單位,然后在空出的最后一個位置增加了一個新的點。
想一下,只要你的顯示器不能夠隨著橫坐標的增長變寬,上面說的就是不得不做的事情。或者除非你不把最前面的那個點淘汰掉,但是那樣的話,你的點只有增,沒有刪,隨著時間的增長,點越來越多,曲線最后只會擠成一團,啥也看不清。
【多說一句,從相對的角度來說,既然可以把圖像往前移一個單位,當然也可以坐標軸往后移一個單位,兩者造成的結果當然是一樣的。
Qt有一個函數scroll可以實現后者的功能,它有兩個參數,可以設置每次x、y軸向右和向上滾動的距離。但是scroll函數繪制坐標軸感覺很奇怪……真的有一種在滾的感覺,看起來很難受,具體可以看Qt歡迎界面里面的一個示例子dynamicspline】
把整個圖畫往前移一個單位這個操作,這就是動態繪圖的核心思想。
除了往前移一個單位這個操作,還要有一個觸發這個操作的信號。
一般來說,當產生動態繪圖這個需求時,都會有一個驅動X軸隨時間變化而增長的因素。或者是傳感器上讀取到一個數據就畫一個點,或者說其它控件傳過來一個數據就畫一個點等等。
如果僅僅是為了學習,也可以聲明一個時間戳對象,當規定的時間戳被觸發一次,就畫一個點。
顯然,傳感器,其它控件,時間戳都是信號,畫圖函數是槽。信號被觸發一次,槽函數就畫一個點。
事先聲明,我沒用過時間戳,我做的項目是手機藍牙傳過來一個RSSI值就畫一個點,之后我貼的代碼也是這樣寫的。
了解了以上兩點,動態繪圖也就沒什么難的了,但是具體還是要看繪圖的軟件提供什么接口來操作。
下面具體說說Qt charts 怎么操作。
Qt charts中,可以主要一下幾個類:?QChart 和 QChartView,QChart是用什么畫,差不多畫筆的意思,QChartView是在什么上畫,差不多畫布的意思。
QChartView?*chartView?=newQChartView(this);
chartView?*chart?=?chartView->chart();
就新建了一個QChartView 和一個 QChart 指針。
類 Series 是用來添加數據的對象(可以理解為一個集合)。常見的QLineSeries,折線類,畫出來的先棱角更強,QSplineSeries,曲線類,畫出來更平滑,QScatterSeries,點類,畫出來是一個個單獨的點。Qt文檔對這些類都有很詳細的說明,并配有圖畫。
類似于QChart 、QChartView、Series ,還有QValueAxis類(數值類型的坐標軸)等等,不再啰嗦,下面的代碼里都有。并且有很詳細的注釋,想學的朋友一定仔細看一遍肯定能看明白。
//新建?一個QLineSeries對象?指針
QLineSeries*?series?=?newQLineSeries();
//?添加數據
series->append(0,?6);
series->append(2,?4);
...
//把series?這條線畫出來
chart->addSeries(series);
主要就是兩個文件mainwindow.h和mainwindow.cpp,我刪掉了一些和繪圖沒關系的變量,程序是不可以運行的,但是繪圖的東西都在里面,可以參考。
#ifndef?MAINWINDOW_H
#define?MAINWINDOW_H
#include?
#include?
#include?
#include?
#include?
QT_CHARTS_USE_NAMESPACE
namespaceUi?{
classMainWindow;
}
classMainWindow?:publicQMainWindow
{
Q_OBJECT
public:
explicitMainWindow(QWidget?*parent?=?0);
~MainWindow();
publicslots:
voidonIBScanTick(QList?list);
private:
Ui::MainWindow?*ui;
intt?=?0;
intmaxy?=?-1000,miny?=?1000;
QString?major_minor?;
QSet?ib_set;
QLineSeries?*series0;
QLineSeries?*series1;
QScatterSeries?*?scatseries0;
QScatterSeries?*?scatseries1;
QChart?*chart;
QChartView?*chartView;
QValueAxis?*axisX2;
QValueAxis?*axisY2;
QValueAxis?*axisX;
QValueAxis?*axisY;
};
#endif?//?MAINWINDO0W_H
#include"mainwindow.h"
#include?"ui_mainwindow.h"
#include?"kalmanfilter.h"
#include?
#include?
#include?"ibscanner/ibscanner.h"
#include?"kalmanfilter_now.h"
#include?"global_data.h"
#include?
MainWindow::MainWindow(QWidget?*parent)?:
QMainWindow(parent),
ui(newUi::MainWindow)
{
ui->setupUi(this);
global_widget*?glw?=?global_widget::inst();
major_minor?=?glw->str;
//設置一些QPen,以便待會設置線條的顏色,寬度
QPen?p0?,p1,p2;
p0.setWidth(3);
p0.setColor(Qt::blue);
p1.setWidth(3);
p1.setColor(Qt::red);
p1.setBrush(Qt::red);
p2.setWidth(3);
p2.setColor(Qt::black);
p2.setBrush(Qt::black);
//QScatterSeries類的點,為了突出每個點的位置,Qcharts畫的出的線每個點的痕跡幾乎看不到
scatseries0?=?newQScatterSeries(this);
scatseries0->setMarkerShape(QScatterSeries::MarkerShapeCircle);//設置點的類型
scatseries0->setMarkerSize(10);?//設置點的大小
scatseries1?=?newQScatterSeries(this);
scatseries1->setMarkerShape(QScatterSeries::MarkerShapeCircle);
scatseries1->setMarkerSize(10);
scatseries1->setPen(p1);
scatseries2?=?newQScatterSeries(this);
scatseries2->setMarkerShape(QScatterSeries::MarkerShapeCircle);
scatseries2->setMarkerSize(10);
scatseries2->setPen(p2);
series0?=?newQLineSeries(this);//線條0
series0->setPen(p0);
series1?=?newQLineSeries(this);//線條1
series1->setPen(p1);
series2?=?newQLineSeries(this);
series2->setPen(p2);
/********************************/
/*設置畫筆和畫布*/
chartView?=?newQChartView(this);
chart?=?chartView->chart();
chart->legend()->hide();?//隱藏圖例
chartView->setRenderHint(QPainter::Antialiasing);?//設置抗鋸齒
chartView->resize(1200,?600);???//畫布大小
chartView->show();?//顯示
/*添加數據*/
chart->addSeries(scatseries0);??//把各個線條添加到chart中
chart->addSeries(scatseries1);
chart->addSeries(scatseries2);
chart->addSeries(series0);
chart->addSeries(series1);
chart->addSeries(series2);
/*設置第一坐標軸*///?rssi?-?dis
axisX?=?newQValueAxis;
axisX->setRange(0,5);???//設置X坐標范圍
axisX->setTitleText("t/s");//設置X坐標名字
axisY?=?newQValueAxis;
axisY->setRange(0,50);
axisY->setTitleText("dis/m");
//別忘記把坐標軸添加到chart
chart->addAxis(axisX,?Qt::AlignTop);??//并且XY軸的位置是上和右
chart->addAxis(axisY,?Qt::AlignRight);
/*?添加第二坐標軸*///t?-?dis
axisX2?=?newQValueAxis;
axisX2->setLabelFormat("%g");
axisX2->setMinorTickCount(15);
axisX2->setTitleText("t/s");
axisX2->setRange(0,5);
axisY2?=?newQValueAxis;
axisY2->setRange(-100,-40);
axisY2->setMinorTickCount(10);
axisY2->setTitleText("dis/m");
chart->addAxis(axisX2,?Qt::AlignBottom);?//并且XY軸的位置是下和左
chart->addAxis(axisY2,?Qt::AlignLeft);
//還要指定這條線是對應的是哪個坐標軸
scatseries0->attachAxis(axisX2);
scatseries0->attachAxis(axisY2);
scatseries1->attachAxis(axisX);
scatseries1->attachAxis(axisY);
scatseries2->attachAxis(axisX2);
scatseries2->attachAxis(axisY2);
series0->attachAxis(axisX2);
series0->attachAxis(axisY2);
series1->attachAxis(axisX);
series1->attachAxis(axisY);
series2->attachAxis(axisX2);
series2->attachAxis(axisY2);
IBScanner*?g?=?IBScanner::instance();
connect(g,?SIGNAL(ibScannerTick(QList)),?this,?SLOT(onIBScanTick(QList)));
g->start();
//getdata();
}
doublegety(intx)
{
intiRssi?=?abs(x);
floatpower?=?(iRssi-46)/(10*3.25);
returnpow(10,?power);
}
voidMainWindow::onIBScanTick(QList?list)//畫圖槽函數
{
QListIterator?it(list);??//這是我接受到的數據
while(it.hasNext())
{
IBResult*?ib?=?it.next();
QString?mac?=?ib->mac;
doubletmp?;
tmp?=?ib->rssi;??//取出我想畫的數據
QString?majMin?=?QString::number(ib->major)?+?QString::number(ib->minor);
//if(!ib_set.contains(majMin))????ib_set.insert(majMin);
if(major_minor?==?majMin)
{
qInfo()?<
if(t?<=?60)//如果點數小于60
{
series0->append(t,tmp);??//把數據添加到series中
scatseries0->append(t,tmp);
series1->append(t,ib->dis);
axisX->setRange(0,t);
scatseries1->append(t,ib->dis);
axisX2->setRange(0,t);??//注意此處,重新設置X軸范圍,保持與像顯示的點數一致
//t++;
}
else//從傳入第61個點開始,就開始滾動,把最早的點扔掉,加最新的一個點
{
//把數據前移一個單位,如果點的數量太多,這里消耗的時間也會很多
QVector?Points?=?series0->pointsVector();
inti;
for(i?=?0;i
{
Points[i]?=?QPoint(t+i,Points[i?+?1].y());
}
Points[Points.size()?-?1]?=?QPoint(t+i,tmp);?//添加最新的點
series0->replace(Points);?//利用replace函數更新數據
scatseries0->replace(Points);
Points?=?series1->pointsVector();
for(i?=?0;i
{
Points[i]?=?QPoint(t+i,Points[i?+?1].y());
}
Points[Points.size()?-?1]?=?QPoint(t+i,ib->dis);
series1->replace(Points);
scatseries1->replace(Points);
axisX2->setRange(t,t+i);
axisX->setRange(t,t+i);
//t++;
}
if(tmp?>?maxy)?maxy?=?tmp;
if(tmp?
axisY2->setRange(std::max(miny?-?5,0)?,?maxy?+?5);
}
/*????????if(majMin?==?"1009135166")??//對不同的藍牙畫另外的線
{
qInfo()?<
if(t?<=?60?)
{
series2->append(t,tmp);//gety(ib->rssi));
scatseries2->append(t,tmp);//gety(ib->rssi));
//t++;
}
else
{
QVector?Points?=?series2->pointsVector();
qInfo()?<
int?i;
for(i?=?0;i
{
Points[i]?=?QPoint(t+i,Points[i?+?1].y());
}
Points[Points.size()?-?1]?=?QPoint(t+i,tmp);//gety(ib->rssi));
series2->replace(Points);
scatseries2->replace(Points);
if(tmp?>?maxy)?maxy?=?tmp;
if(tmp?
}
//t++;
}
*/
if(major_minor?==?majMin?||?majMin?=="1009135166")
{
axisY2->setRange(miny,?maxy?+?5);
t++;
}
}
}
MainWindow::~MainWindow()
{
deleteui;
}
總結
以上是生活随笔為你收集整理的qchart折现图_Qt Charts 动态实时折线图绘制的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 灵芝孢子粉多少钱啊?
- 下一篇: 热带飓风和虎名画是谁画的啊?