MFC中繪製動態曲線
https://blog.csdn.net/zang141588761/article/details/50536788
在工控監測領域,經常需要動態繪製曲線,觀察曲線的變化趨勢,繪製波形圖,繪製頻譜等。在前面4講中介紹了MFC經常用的TeeChart控制元件和Hight-Speed
Chart Ctrl,這兩個都是MFC繪圖控制元件的經典(另外,在Qt中還有QwtPlot和QCustomPlot兩大神器)。許多人問如何繪製動態變化的曲線,為此專門寫下這篇文章。
C++ GUI 繪圖控制元件目錄 MFC(VC)
Qt
|
對於任何繪圖控制元件,都可以實現動態繪圖,其原則是:控制元件只負責繪圖,若想曲線動,就讓資料動,就像看電影一樣,電影是由一幀一幀的靜態圖片組合起來的,在一定速度上重新整理,靜態圖片就能動起來;和電影的原理一樣,繪圖控制元件能顯示靜態的曲線,想要它動起來,就讓它頻在一定時間重新整理就可以了。 |
這就是動態繪圖的實現原理。
實現動態曲線需要以下兩個準備:
- 計時器Timer
- 陣列左移
基於Timer的繪圖
任何介面庫都會有Timer這個實現,在MFC中時OnTimer訊息,在Qt中是QTimer類,那種原理基本都一樣,下面將以MFC(VC)為例進行說明。
Timer是訊息級別最低的訊息,它會保證其它級別高的訊息優先執行,因此,就算資料大量重新整理,也不會影響主執行緒的其它訊息。
MFC生成OnTimer訊息,訊息響應函式如下:
[cpp] view plain copy
- void CTeeChartDlg::OnTimer(UINT_PTR nIDEvent)
- {
- // TODO: 在此新增訊息處理程式程式碼或呼叫預設值
- CDialogEx::OnTimer(nIDEvent);
- }
繪圖的實現就在這個訊息響應函式裡
如果讓定時器設定為1秒觸發,每一秒把舊資料去除,繪製新資料,就能看到不停變換的波形;對於趨勢圖,假如每秒有一個新資料,那麼就在定長陣列中,把陣列所有資料整體左移,同時陣列末端加入新資料。程式碼如下:
[cpp] view plain copy
- ///
- /// \brief 左移陣列
- /// \param ptr 陣列指標
- /// \param data 新數值
- ///
- void LeftMoveArray(double* ptr,size_t length,double data)
- {
- for (size_t i=1;i<length;++i)
- {
- ptr[i-1] = ptr[i];
- }
- ptr[length-1] = data;
- }
這樣,陣列就實現“向左運動”,把左移後的陣列繪製,就能在繪圖控制元件上發現其變化。
下面開始實現動態繪圖(這裡演示TeeChart的方法,附件裡有HightSpeed-Chart CChartCtrl的方法):
[cpp] view plain copy
- void CTeeChartDlg::OnBnClickedButtonRuning()
- {
- KillTimer(0);
- ZeroMemory(&m_TeeChartArray,sizeof(double)*m_c_arrayLength);
- for (size_t i=0;i<m_c_arrayLength;++i)
- {
- m_X[i] = i;
- }
- m_count = m_c_arrayLength;
- CSeries chart_T = (CSeries)m_Chart.Series(0);
- chart_T.Clear();
- m_pLineSerie->ClearSerie();
- SetTimer(0,1000,NULL);
- }
[cpp] view plain copy
- double m_TeeChartArray[2096];
- double m_X[2096];
- unsigned int m_count;
- const size_t m_c_arrayLength = 2096;
m_TeeChartArray是需要繪製的陣列的Y值,m_X是對應的x值,m_count是計數器,每繪製一次,個數加1,主要用於x軸
在timer中的實現如下:
[cpp] view plain copy
- void CTeeChartDlg::OnTimer(UINT_PTR nIDEvent)
- {
- // TODO: 在此新增訊息處理程式程式碼和/或呼叫預設值
- if(0 == nIDEvent)
- {
- ++m_count;
- drawMoving();
- }
- CDialogEx::OnTimer(nIDEvent);
- }
drawMoving函式用於繪圖,timer設定為1秒觸發一次,這時就能看到每秒的變化,如果資料是以1秒為重新整理週期,每一秒有個新資料,只需要把舊的資料向左移,新資料放到陣列最右端,再在繪圖控制元件上把此圖形畫出來即可看的像動一樣。
drawMoving函式的實現如下:
[cpp] view plain copy
- void CTeeChartDlg::drawMoving()
- {
- CSeries chart_T = (CSeries)m_Chart.Series(0);
- chart_T.Clear();
- m_pLineSerie->ClearSerie();
- LeftMoveArray(m_TeeChartArray,m_c_arrayLength,randf(0,10));
- LeftMoveArray(m_X,m_c_arrayLength,m_count);
- DrawLine_TeeChart(m_X,m_TeeChartArray,m_c_arrayLength);
- }
前面說過timer是優先順序最低的訊息,如果想曲線動的流暢,可以把時鐘設定為0ms,如
[cpp] view plain copy
- SetTimer(0,0,NULL);
上面介紹的就是動態繪製曲線的思路和方法,附件中有用TeeChart實現和HightSpeedChart實現的例子,考慮到可能有些人沒有安裝TeeChart,專門把TeeChart分離出來了一個原始碼,只有HightSpeedChart,不需要安裝任何控制元件。
demo1:
MFC下TeeChart和HightSpeedChart動態繪製曲線圖-VS2010
demo2(不用安裝任何控制元件):