MFC 動態曲線 支援縮放 顯示圖例(CStatic派生類)
首先宣告,本專案不是作者獨立完成的,而是藉助別人的修改得到,也不保證目前的版本沒有Bug,僅供大家參考和交流。若有不妥之處,還望指正。
之所以標為“原創”,是因為作者的確花了很大心思,並做了大幅修改和整理,望廣大網友包涵,哈哈。。。
開發環境:Windows 7 ,Visual Studio 2008。
(一)開發需求和目標
由於專案需要,需要開發一個GUI,要求能夠同時顯示至少兩條曲線,而且要標出座標,動態更新,支援縮放。。。。
(二)本專案實現了哪些功能
繼承CStatic控制元件,編寫了一個繪圖類,可以同時顯示多條曲線,顯示橫縱座標,座標的範圍可以自動調整,支援單擊滑鼠左鍵拖動放大,雙擊滑鼠左鍵復原(這個想法來自MATLAB)。曲線和座標軸屬性可以自行設定。能夠顯示圖例。
(三)效果截圖
區域性放大的結果:
(四)原始碼
這個部落格不能新增附件,暈。。。 那個CSDN的檔案要收兩個積分的,大家不要介意哦。。。
備註,為了減小檔案大小,我講Debug和Release資料夾加下的檔案,請大家編譯後執行。
好了,一般人看到這裡就可以了,下面贅述一下整個開發過程。
(一)關於參考程式
上面這篇參考博文寫的不錯,而且附了源程式可供下載,但是實際執行我發現有記憶體洩漏!本人不是有意詆譭原作者的心血,只是實事求是,歡迎討論。
記憶體洩漏的原因不得而知,不過我學到了記憶體洩漏的檢測方法,順便說一下:
一是 Visual Studio自帶的,這個微軟MSDN上有說,包含如下語句:
#define _CRTDBG_MAP_ALLOC
#include<stdlib.h>
#include<crtdbg.h>
#include "debug_new.h"
然後在每個要檢測的函式後面新增:
_CrtDumpMemoryLeaks();
這樣在輸出視窗會顯示是否出現了記憶體洩漏,並定位;
(二)雙緩衝繪圖
既然參考的程式有記憶體洩漏的問題,那隻能自己動手了。
像我這種菜鳥,拿到這個專案,當然先去網上搜”MFC 動態曲線“,”VC++ 動態繪圖“,”MFC GDI+ 繪圖“等等,看多了,對雙緩衝繪圖也就耳濡目染了。
雖然我對具體實現還不是很瞭解,大概知道了其過程:現在記憶體中高個Bitmap物件,繪製完成後,拷貝到前端。這樣就不用先擦出前端的影象,再一步一步繪製。雙緩衝的好處
就是避免閃爍,這個大家都懂的。。。
關於雙緩衝繪圖的過程大致如下:
CPaintDC dc(this); // 繪圖裝置
CDC *pDC = GetDC();
CRect rect;
GetClientRect (&rect);
//建立一個記憶體中的顯示裝置
CDC nDC;
nDC.CreateCompatibleDC(NULL);
//建立一個記憶體中的影象
CBitmap nBitmap;
nBitmap.CreateCompatibleBitmap(pDC, rect.Width(),rect.Height());
//指定記憶體顯示裝置在記憶體中的影象上畫圖
nDC.SelectObject(&nBitmap);
// 重新整理控制元件
RefreshPlot(&nDC);
//將記憶體中畫好的影象直接拷貝到螢幕指定區域上
pDC->BitBlt(rect.left,rect.top,rect.right,rect.bottom,&nDC, 0, 0, SRCCOPY);
//釋放相關資源
nBitmap.DeleteObject();
nDC.DeleteDC();
ReleaseDC(pDC);
其他的沒有好說的,重點是RefreshPlot()方法,這個是我自定義的函式。其內部完成:繪製背景、座標軸、網格、曲線、網格座標的顯示、標題的顯示、圖例顯示。。。。。
這部分程式碼是放在過載的OnPaint()函式中的。
(三)繪圖結構和方法
根據從網上查詢的資料,我見過三種繪圖結構。這裡說的繪圖結果,意思上,將上面的哪些程式碼(繪圖的具體細節)貼到那個函式中去,我見過的三種情況是:過載:
DrawItem()方法,過載OnPaint()方法,過載OnEraseBkgnd()方法。貌似都可以,但是某些可能需要一些其他輔助的設定。本專案是採用的第二種方法。
除了結構外最重要的便是具體怎麼在一個CDC上繪圖了。其實非常簡單,只用幾個函式,下面簡單介紹一下:(pDC是CDC物件的指標)
pDC->MoveTo(int x,int y); 移動到一個點(CPoint的物件),x,y是點的座標,關於MFC上繪圖座標大家應該非常熟悉了吧,左上為座標原點,X軸向右,Y軸向下。
當然也可以選擇使用過載 MoveTo(POINT point)方法,預先把點算好,然後MoveTo()就好了。
pDC->LineTo(int x,int y); 這個函式意思很明顯,畫一條線,起點是上一給點,終點是當前的點(x,y),上一個點可以是MoveTo()確定的,或是LineTo()確定的。
上面兩個函式可以完成哪些工作呢?只要是直線都可以,如繪製座標軸,繪製網格,和繪製曲線。繪製曲線其實就是呼叫多次LineTo()就OK啦
另一個函式是pDC->DrawText(),這個函式是用來顯示文字的,當然繪製文字之前得告訴它目標位置、文字格式、顏色等等資訊,這個後面會有介紹。
有個這三個函式,基本就大功告成了,剩下的便是控制位置的格式和位置。這裡要介紹三個物件:CPen,CFont和CRect。
CPen:畫筆,其中的一個建構函式為CPen(int nPenStyle,int nWidth,COLORREF crColr),畫線的時候用到,
CFont:字型,一般這麼用 font.CreatePointFont(int nPointSize, LPCTSTR lpszFaceName, CDC* pDC = NULL) ,font為CFont的一個物件,這個在繪製文字的時候用到
CRect:矩形,構造的時候指明四個座標值left,top,right,bottom就好了,這個在佈局的時候和繪製文字會用到。
現在就可以開始繪圖啦,步驟:
①pDC->SelectObject(& font\pen),選擇好畫筆,格式由內部的引數font或者pen的引用指定;
②pDC->DrawText()或者pDC->MoveTo() + pDC->LineTo(),繪圖;
③pDC->SelectObject(CPen * oldPen),恢復畫筆。
無論是繪製哪個部分,都套用上述三個步驟,就OK啦。
關於佈局和縮放的功能就留作後面介紹吧。
參考: