轉帖|使用教程|編輯:鮑佳佳|2021-07-20 10:41:09.000|閱讀 484 次
概述:在MFC中,CGdiObject類是GDI對象的基類,通過查閱MSDN我們可以看到,CGdiObject類有六個直接的派生類,在這六個GDI對象中,最常用的莫過于畫筆和畫刷了,即CPen類和CBrush類。本文就主要講解畫筆的使用。
# 界面/圖表報表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
相關鏈接:
上一節中講了CDC類及其屏幕繪圖函數,本節的主要內容是GDI對象之畫筆CPen。
GDI對象
在MFC中,CGdiObject類是GDI對象的基類,通過查閱MSDN我們可以看到,CGdiObject類有六個直接的派生類,GDI對象主要也是這六個,分別是:CBitmap、CBrush、CFont、CPalette、CPen和CRgn。
在這六個GDI對象中,最常用的莫過于畫筆和畫刷了,即CPen類和CBrush類。本文就主要講解畫筆的使用。
畫筆的應用實例
在這里直接通過一個波形圖的實例,來詳細講解畫筆的使用方法。
首先介紹此實例要實現的功能:在對話框上有一個Picture控件,將此控件的背景填充為黑色;啟動一個定時器,每次定時器到時,所有波形數據都前移一個單位,并獲取一個80以內的隨機數作為波形的最后一個數據,然后以綠色畫筆在繪圖控件上繪制波形。這樣就實現了波形的繪制及動態變化。
下面是具體實施步驟:
1、創建一個基于對話框的MFC工程,名字設為“Example50”。
2、在自動生成的對話框模板IDD_EXAMPLE50_DIALOG中,刪除“TODO: Place dialog controls here.”添加一個Picture控件,ID設為IDC_WAVE_DRAW。
3、為Picture控件IDC_WAVE_DRAW添加CStatic變量,名稱設為m_picDraw。
4、在文件Example50Dlg.h文件中CExample50Dlg類聲明的上面添加宏定義:
此符號常量的意義是波形的點數,這里用define將其定義為符號常量是為了方便以后可能的修改,假如我們以后想將點數改為200,則只改此宏定義就可以了:#define POINT_COUNT 200,而如果沒有使用符號常量,在程序中直接使用了100,那么就需要將所有使用100的位置找出來,并替換為200,這樣不僅麻煩也很容易出錯,所以最好是將其定義為符號常量。
5、在CExample50Dlg.h文件中為CExample50Dlg類添加成員數組:
此數組用于存放波形數據。
6、在CExample50Dlg類的構造函數中為數組m_nzValues的元素賦初值:
C++代碼
CExample50Dlg::CExample50Dlg(CWnd* pParent /*=NULL*/) : CDialogEx(CExample50Dlg::IDD, pParent) { m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); // 將數組m_nzValues的元素都初始化為0 memset(m_nzValues, 0, sizeof(int) * POINT_COUNT); }
7、在CExample50Dlg對話框的初始化成員函數CExample50Dlg::OnInitDialog()中,構造隨機數生成器,并啟動定時器。CExample50Dlg::OnInitDialog()修改如下:
C++代碼
BOOL CExample50Dlg::OnInitDialog() { CDialogEx::OnInitDialog(); // Add "About..." menu item to system menu. // IDM_ABOUTBOX must be in the system command range. ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); ASSERT(IDM_ABOUTBOX < 0xF000); CMenu* pSysMenu = GetSystemMenu(FALSE); if (pSysMenu != NULL) { BOOL bNameValid; CString strAboutMenu; bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX); ASSERT(bNameValid); if (!strAboutMenu.IsEmpty()) { pSysMenu->AppendMenu(MF_SEPARATOR); pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); } } // Set the icon for this dialog. The framework does this automatically // when the application's main window is not a dialog SetIcon(m_hIcon, TRUE); // Set big icon SetIcon(m_hIcon, FALSE); // Set small icon // TODO: Add extra initialization here // 以時間為種子來構造隨機數生成器 srand((unsigned)time(NULL)); // 啟動定時器,ID為1,定時時間為200ms SetTimer(1, 200, NULL); return TRUE; // return TRUE unless you set the focus to a control }
8、為CExample50Dlg類添加波形繪制的成員函數CExample50Dlg::DrawWave(CDC *pDC, CRect &rectPicture),參數分別為設備上下文指針和繪圖的矩形區域。
C++代碼
void CExample50Dlg::DrawWave(CDC *pDC, CRect &rectPicture) { float fDeltaX; // x軸相鄰兩個繪圖點的坐標距離 float fDeltaY; // y軸每個邏輯單位對應的坐標值 int nX; // 在連線時用于存儲繪圖點的橫坐標 int nY; // 在連線時用于存儲繪圖點的縱坐標 CPen newPen; // 用于創建新畫筆 CPen *pOldPen; // 用于存放舊畫筆 CBrush newBrush; // 用于創建新畫刷 CBrush *pOldBrush; // 用于存放舊畫刷 // 計算fDeltaX和fDeltaY fDeltaX = (float)rectPicture.Width() / (POINT_COUNT - 1); fDeltaY = (float)rectPicture.Height() / 80; // 創建黑色新畫刷 newBrush.CreateSolidBrush(RGB(0,0,0)); // 選擇新畫刷,并將舊畫刷的指針保存到pOldBrush pOldBrush = pDC->SelectObject(&newBrush); // 以黑色畫刷為繪圖控件填充黑色,形成黑色背景 pDC->Rectangle(rectPicture); // 恢復舊畫刷 pDC->SelectObject(pOldBrush); // 刪除新畫刷 newBrush.DeleteObject(); // 創建實心畫筆,粗度為1,顏色為綠色 newPen.CreatePen(PS_SOLID, 1, RGB(0,255,0)); // 選擇新畫筆,并將舊畫筆的指針保存到pOldPen pOldPen = pDC->SelectObject(&newPen); // 將當前點移動到繪圖控件窗口的左下角,以此為波形的起始點 pDC->MoveTo(rectPicture.left, rectPicture.bottom); // 計算m_nzValues數組中每個點對應的坐標位置,并依次連接,最終形成曲線 for (int i=0; i<POINT_COUNT; i++) { nX = rectPicture.left + (int)(i * fDeltaX); nY = rectPicture.bottom - (int)(m_nzValues[i] * fDeltaY); pDC->LineTo(nX, nY); } // 恢復舊畫筆 pDC->SelectObject(pOldPen); // 刪除新畫筆 newPen.DeleteObject(); }
9、有了定時器和繪圖成員函數,我們就可以在WM_TIMER消息的響應函數中添加對波形數據的定時處理和對波形的定時繪制了。定時器及WM_TIMER消息處理函數的添加方法如果忘記了,可以再到溫習下。
WM_TIMER消息的處理函數修改如下:
C++代碼
void CExample50Dlg::OnTimer(UINT_PTR nIDEvent) { // TODO: Add your message handler code here and/or call default CRect rectPicture; // 將數組中的所有元素前移一個單位,第一個元素丟棄 for (int i=0; i<POINT_COUNT-1; i++) { m_nzValues[i] = m_nzValues[i+1]; } // 為最后一個元素賦一個80以內的隨機數值(整型) m_nzValues[POINT_COUNT-1] = rand() % 80; // 獲取繪圖控件的客戶區坐標 // (客戶區坐標以窗口的左上角為原點,這區別于以屏幕左上角為原點的屏幕坐標) m_picDraw.GetClientRect(&rectPicture); // 繪制波形圖 DrawWave(m_picDraw.GetDC(), rectPicture); CDialogEx::OnTimer(nIDEvent); }
10、在對話框銷毀時,定時器應關閉。所以為CExample50Dlg類添加WM_DESTROY消息的處理函數,并修改如下:
C++代碼
void CExample50Dlg::OnDestroy() { CDialogEx::OnDestroy(); // TODO: Add your message handler code here // 關閉定時器 KillTimer(1); }
11、一切準備就緒,編譯運行。最終的效果如下圖:
關于畫筆,今天就講到這里了,下一節將為大家簡單講講畫刷的使用。謝謝大家的關注!
本站文章除注明轉載外,均為本站原創或翻譯。歡迎任何形式的轉載,但請務必注明出處、不得修改原文相關鏈接,如果存在內容上的異議請郵件反饋至chenjj@fc6vip.cn
文章轉載自: