MFC繪圖2-客戶區大小和DC
客戶區大小和DC
在繪圖前,必須先獲得客戶區大小和設備上下文DC。
1.得到客戶區
繪圖通常都是在視圖窗口的客戶區進行,而客戶區的大小在運行時可由用戶改變,爲了使繪製的圖形能隨窗口大小自動改變,必須先獲得當前客戶區大小的數據(寬w和高h)。
獲取客戶區大小的方法有以下兩種:
1)在消息響應函數OnSize中得到
利用屬性窗口的信息頁,在視圖類中添加WM_SIZE消息的響應函數OnSize。該函數在窗口第一次顯示或窗口大小被改變時會被Windows系統調用。其輸入參數中的cx和cy就是客戶區大小的寬和高,可將它們賦值給類變量(如m_iW和m_iH)供繪圖時使用。例如
void CDrawView::OnSize(UINT nType, int cx, int cy) {
CView::OnSize(nType, cx, cy);
// TODO: 在此處添加消息處理程序代碼
m_iW = cx; m_iH = cy;
}
其中,nType的值爲:
<!--[if !supportLists]-->l <!--[endif]-->SIZE_MAXIMIZED(窗口已被最大化)
<!--[if !supportLists]-->l <!--[endif]-->SIZE_MINIMIZED(窗口已被最小化)
<!--[if !supportLists]-->l <!--[endif]-->SIZE_RESTORED(窗口已被改變大小)
<!--[if !supportLists]-->l <!--[endif]-->SIZE_MAXHIDE(其餘窗口被最大化)
<!--[if !supportLists]-->l <!--[endif]-->SIZE_MAXSHOW(其餘窗口從最大化還原)
2)調用成員函數GetClientRect獲得
可在繪圖前,定義一個矩形變量rect,而後再調用CWnd類的成員函數GetClientRect:
void GetClientRect( LPRECT lpRect ) const;
獲得當前客戶區矩形的數據,其中的右(right)與底(bottom)就是客戶區的寬與高(其左left與頂top都爲0)。例如:
RECT rect;
GetClientRect(&rect);
int w = rect.right, h = rect.bottom;
2.DC
在Windows中,繪圖使用的是MFC的DC(Device-Context, 設備上下文)類CDC中各類繪圖函數。
0)CDC類
CDC是CObject的直接派生類,CDC類本身也有若干派生類,其中包括窗口客戶區DC所對應的CClientDC類、OnPaint和OnDraw消息響應函數的輸入參數中使用的CPaintDC類、圖元文件對應的 CMetaFileDC類和整個窗口所對應的CWindowDC類。
CDC類中有許多成員函數,能夠用來設置各類繪圖環境、屬性和參數,以及繪製各類圖形和圖像等,將在後面陸續加以介紹。
1)得到DC
能夠從OnDraw函數的輸入參數pDC或調用CWnd的成員函數GetDC:
CDC* GetDC( );
來得到DC的指針。
2)釋放DC
由於Windows限制可用DC的數量,因此DC屬於稀缺的公用資源。所以,對每次得到的DC,在使用完成後必須當即釋放。
從OnDraw函數的輸入參數pDC得到的DC,在該函數運行結束後,系統會自動釋放。但由GetDC所得到的DC,必須本身來釋放,這能夠經過調用CWnd的成員函數ReleaseDC來完成:
int ReleaseDC( CDC* pDC ); // 成功返回非0
例如:
void CDrawView::OnLButtonUp(UINT nFlags, CPoint point)
{
ReleaseCapture();
if (m_bLButtonDown) {
CDC* pDC = GetDC();
pDC->SelectObject(new CPen(PS_SOLID, 0, RGB(255, 0, 0)));
pDC->SelectStockObject(NULL_BRUSH);
pDC-> Ellipse (rect);
ReleaseDC(pDC);
m_bLButtonDown = FALSE;
}
CView::OnLButtonUp(nFlags, point);
}
3)類DC
每次從OnDraw函數的輸入參數或調用GetDC所得到的DC,都是一個全新的臨時缺省DC。它不能用類變量來長期保存,並且原來選入的各類GDI對象全都被做廢,必須從頭再來。
爲了使選入的各類GDI對象一直有效,必須在視圖類的PreCreateWindow函數中調用CWnd類的成員函數AfxRegisterWndClass:
LPCTSTR AFXAPI AfxRegisterWndClass( UINT nClassStyle, HCURSOR hCursor = 0,
HBRUSH hbrBackground = 0, HICON hIcon = 0 );
來修改窗口類的風格屬性中的DC爲類DC:CS_CLASSDC。如
BOOL CDrawView::PreCreateWindow(CREATESTRUCT& cs) {
cs.lpszClass = AfxRegisterWndClass(CS_DBLCLKS | CS_HREDRAW |
CS_VREDRAW | CS_CLASSDC, 0,
::CreateSolidBrush(RGB(255, 255, 255)));
return CView::PreCreateWindow(cs);
}
4)安全DC句柄
也能夠用CDC類的成員函數:
HDC GetSafeHdc();
來獲取CD所對應窗口(如客戶區)的安全DC句柄,該句柄在窗口存在期間一直是有效的。例如,可先定義類變量HDC m_hDC;,再在適當的地方給它賦值m_hDC = GetDC()->GetSafeHdc();,而後就能夠放心地使用了。例如,可使用CDC類的成員函數
BOOL Attach(HDC hDC); // 成功返回非0
來將CDC對象與DC句柄鏈接在一塊兒。