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