QtChart——簡單的動態波形圖
眾所周知Qt 5.7過後Qt添加了官方的Chart庫,終於可以用官方的庫替代QWT和QCustomerPlot。本文只是簡單的融合了幾個Qt官方例子。程式執行圖如下:
功能點
其實大家來看部落格,就是來看有啥功能,能ctrl + C加ctrl + V到自己專案裡的,至於原理,有興趣的同學可以自己去看看Qt原始碼,所以這裡就主要講一下本例有什麼功能:
- 資料動態更新。例子裡是定時器,定時更新一個正弦波。
- 放大縮小。通過滑鼠滾輪實現影象放大縮小功能。
- 比例復原。當你不小心把影象弄丟了,沒關係,點選一下滑鼠右鍵就行了。
- 座標顯示。滑鼠懸停到資料線條上就會顯示,XY座標的值。
- 影象拖拽。不能拖拽那有啥意思?
接下來就簡單講解一下每個功能點的簡單實現,基礎知識我就不講了,因為我也不知道,寫程式碼就是一個搬運的過程。
資料動態更新
說道資料動態更新,但凡用過QWT和QCustomerPlot的同學都知道,這樣做:
QVector<QPointF> data;
if (data.size() > max) {
data.pop_back();
data.push_front(point);
} else {
data.push_front(point);
}
每次只需要把最後的資料彈出去,然後新增新的資料就OK了,但是QChart這個地方有點意思,到替換原來資料的時候,前面資料和後面資料就連一起了,一條好好的正弦波多了一條線,肯定不爽啊。然後就看了Qt的Example,在audio那,就是音訊資料採集那,但凡做過AD資料採集的同學應該都懂,然後我當然就把那的程式碼化為己有了:
void MainWidget::updateData()
{
int i;
QVector <QPointF> oldData = series->pointsVector();
QVector<QPointF> data;
if (oldData.size() < 97) {
data = series->pointsVector();
} else {
/* 新增之前老的資料到新的vector中,不復制最前的資料,即每次替換前面的資料
* 由於這裡每次只新增1個數據,所以為1,使用時根據實際情況修改
*/
for (i = 1; i < oldData.size(); ++i) {
data.append(QPointF(i - 1 , oldData.at(i).y()));
}
}
qint64 size = data.size();
/* 這裡表示插入新的資料,因為每次只插入1個,這裡為i < 1,
* 但為了後面方便插入多個數據,先這樣寫
*/
for(i = 0; i < 1; ++i){
data.append(QPointF(i + size, 10 * sin(M_PI * count * 4 / 180)));
}
series->replace(data);
count++;
}
清楚明瞭,每次都需要copy一次資料,不過這種方法效率不知道怎麼樣,普通的採集還好,我之前公司的專案,收資料是按us級來搞的,所以之前用QCustomerPlot效果也不太好,一次replot()就是3個ms(畢竟QCustomerPlot的底層也是copy了一次資料= =!),那我得漏多少條資料。。。
放大縮小
這個就比較好搞,一個滑鼠滾輪事件:
void MainWidget::wheelEvent(QWheelEvent *event)
{
if (event->delta() > 0) {
chart->zoom(1.1);
} else {
chart->zoom(10.0/11);
}
QWidget::wheelEvent(event);
}
比例自己定,這裡我的是比例是10%。
比例復原
其實就呼叫了一個zoomReset()函式:
void ChartView::mousePressEvent(QMouseEvent *event)
{
if (event->button() & Qt::LeftButton) {
isClicking = true;
} else if (event->button() & Qt::RightButton) {
chart()->zoomReset();
}
QChartView::mousePressEvent(event);
}
座標顯示
改自官方Example的Callout,其實我就改了一下命名,因為有程式碼潔癖,不習慣匈牙利命名法,C++喜歡用駝峰,C語言還是K&C,然後內容沒改,但願不會被查水錶,具體程式碼就不貼了,下面發整個工程的程式碼連結。
影象拖拽
就是一個mousePressEvent和mouseMoveEvent事件,滑鼠按下了把標誌位變為true,然後在滑鼠Move的時候檢測標誌位是否為true,如果是就根據座標計算scroll值:
void ChartView::mouseMoveEvent(QMouseEvent *event)
{
int x, y;
if (isClicking) {
if (xOld == 0 && yOld == 0) {
} else {
x = event->x() - xOld;
y = event->y() - yOld;
chart()->scroll(-x, y);
}
xOld = event->x();
yOld = event->y();
return;
}
QChartView::mouseMoveEvent(event);
}