Windows程式設計__孫鑫C++Lesson4《繪圖操作》
本節要點:
1.訊息捕獲對象
2.MFC訊息映射機制
3.MFC繪圖操作
4.靜態成員函數與靜態變數
//*****************************************************************************
1.view類在架構類之上,因此架構類無法捕獲WM_LBUTTONDOWN訊息
2.MFC訊息映射
其中的一種思路是:基類定義所有的虛函數,但MFC類間關係複雜,不宜採用這種方式;
MFC訊息映射機制要點:
(1)訊息和具體視窗相關, MFC維護了一個控制代碼與c++類指標映射,通過控制代碼能找到C++類對象的指標;
(2)子類指標傳遞給基類,基類調用CWnd::WindowProc處理,其函數原型為:
virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam);
virtual BOOL OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult);
可以看出他們均為虛函數。在CWnd::WindowProc會調用CWnd::OnWndMsg處理;
(3)CWnd::OnWndMsg會通過訊息映射宏之間的函數原型聲明尋找訊息映射,如果子類沒有添加訊息響應則由父類處理.
MFC架構提供的宏實現訊息映射:
(1)注釋宏 表示函數原型是訊息響應的原型聲明
//{{AFX_MSG(CDrawView)
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
//}}AFX_MSG
(2)訊息映射宏 ,關聯訊息響應函數
BEGIN_MESSAGE_MAP(CDrawView, CView)
//{{AFX_MSG_MAP(CDrawView)
ON_WM_LBUTTONDOWN()
//}}AFX_MSG_MAP
// Standard printing commands
ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)
END_MESSAGE_MAP()
(3)添加訊息響應函數
void CDrawView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
CView::OnLButtonDown(nFlags, point);
}
3.MFC繪圖函數
(1)畫直線實現
//WIn32 SDK平台下實現
HDC hdc;
hdc=::GetDC(m_hWnd);//CDrawView從CWnd派生而來 m_hWnd儲存了控制代碼
::MoveToEx(hdc,m_ptOrigin.x,m_ptOrigin.y,NULL);
LineTo(hdc,point.x,point.y);
::ReleaseDC(m_hWnd,hdc);
//*****************************************************************************
//MFC封裝的CDC類實現
CDC* pDC=GetDC();
pDC->MoveTo(m_ptOrigin);
pDC->LineTo(point);
ReleaseDC(pDC);
//*****************************************************************************
//用CClientDC實現
//CClientDC DC關聯了客戶區
//CClientDC dc(this);//View類建立DC在客戶區作圖
/*CClientDC dc(GetParent());//構造主架構的DC在客戶區作圖
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);*/
//*****************************************************************************
//用CWindowDC實現
//CWindowDC 可訪問視窗的客戶區和非客戶區
//CWindowDC dc(this);//View類建立DC在客戶區作圖
//CWindowDC dc(GetParent());//在架構客戶區和非客戶區作圖
//CWindowDC dc(GetDesktopWindow());//dc與整個桌面視窗相關 可以在整個視窗作圖
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);
//*****************************************************************************
//畫筆建立與選擇
CClientDC dc(this);
CPen pen(PS_SOLID,1,RGB(255,0,0));
CPen *pOldPen=dc.SelectObject(&pen);
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);
dc.SelectObject(pOldPen);
作圖效果如:
//*****************************************************************************
//畫刷建立與填充矩
CClientDC dc(this);
CBrush brush(RGB(255,0,0));
dc.FillRect(CRect(m_ptOrigin,point),&brush); //傳遞畫刷指標時,不需要選中畫刷
//*****************************************************************************
//位元影像畫刷建立與填充矩形地區
CClientDC dc(this);
CBitmap bitmap;
bitmap.LoadBitmap(IDB_BITMAP1);//IDB_BITMAP1為位元影像的資源ID
CBrush brush(&bitmap);
dc.FillRect(CRect(m_ptOrigin,point),&brush);
作圖效果如:
//*****************************************************************************
//透明畫刷(空話刷建立)
CClientDC dc(this);
CBrush * pBrush=CBrush::FromHandle( (HBRUSH)GetStockObject(NULL_BRUSH) );
CBrush * pOldBrush=dc.SelectObject(pBrush);
dc.Rectangle(CRect(m_ptOrigin,point));
dc.SelectObject(pOldBrush);
效果如:
//*****************************************************************************
關於ReleaseDC:
函數原型: int ReleaseDC( CDC* pDC );
MSDN 注釋 The application must call the ReleaseDC method for each call to the GetWindowDC method and for each call to the GetDC method.
關於客戶區與非客戶區:
架構的客戶區從工具列開始向下,View類客戶區在工具列之下的地區,非客戶區包括標題列和功能表列.
(2)畫連續線
//****************************************************************************
//連續線條
CClientDC dc(this);
CPen pen(PS_SOLID,1,RGB(255,0,0));
CPen *pOldPen=dc.SelectObject(&pen);
if(IsLbuttonDow)
{
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);
m_ptOrigin=point;//原點值更改
}
dc.SelectObject(pOldPen);
效果如:
(3)畫扇形
//*****************************************************************************
//扇形
CClientDC dc(this);
CPen pen(PS_SOLID,1,RGB(255,0,0));
CPen *pOldPen=dc.SelectObject(&pen);
if(IsLbuttonDow)
{
dc.MoveTo(m_ptOrigin);
dc.LineTo(m_ptOld);
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);
m_ptOld=point;
}
dc.SelectObject(pOldPen);
//*****************************************************************************
//帶邊線的扇形
CClientDC dc(this);
CPen pen(PS_SOLID,1,RGB(255,0,0));
CPen *pOldPen=dc.SelectObject(&pen);
if(IsLbuttonDow)
{ ////SetROP2 設定繪畫模式
//dc.SetROP2(R2_MERGENOTPEN); 看不見線條
//dc.SetROP2(R2_BLACK);//黑色
dc.MoveTo(m_ptOrigin);
dc.LineTo(m_ptOld);
dc.MoveTo(m_ptOld);
dc.LineTo(point);
m_ptOld=point;
}
dc.SelectObject(pOldPen);
效果如:
4.靜態函數與靜態變數
在建立透明畫刷時,語句CBrush * pBrush=CBrush::FromHandle( (HBRUSH)GetStockObject(NULL_BRUSH) );中調用了CBrush類的靜態成員函數完成了指標轉換.
該函數原型為:static CBrush* PASCAL FromHandle( HBRUSH hBrush );
關於靜態成員函數與變數要點:
(1)靜態方法屬於類本身 不屬於具體對象 類載入時已經分配記憶體,可以再類外調用
(2)態成員變數必須在類的定義外部初始化,非靜態成員在類未執行個體化時尚未分配記憶體空間
Win32 Console Application Test.cpp 實驗代碼如下:
//*****************************************************************************
#include <iostream.h>
class Point
{
public:
void output()
{
x=0;
y=0;
init();//可以引用靜態成員方法 從記憶體模型來考慮
}
static void init()//靜態方法 對象沒有產生之前已經存在於記憶體 而非靜態成員x,y尚未分配記憶體空間
{
//x=0,y=0;// error C2597: illegal reference to data member 'Point::x' in a static member function
a=0;//error LNK2001: unresolved external symbol "private: static int Point::b" (?b@Point@@0HA)
b=0;//靜態成員變數必須在類的定義外部初始化
}
private:
int x,y;
static int a,b;
};
int Point::a=0;
int Point::b=0;//靜態成員的初始化在類外實現
void main()
{
//Point pt;
//pt.init();
//pt.output();
Point::init();//靜態方法屬於類本身 不屬於具體對象 類載入時已經分配記憶體
//error C2352: 'Point::output' : illegal call of non-static member function
//Point::output();//內部成員必須實實在在存在記憶體空間才能調用這個方法
}
//*****************************************************************************
本節小結:
1.Win32 SDK平台函數很好用,但是在類內部用成員函數更方便.
2.繪圖類CDC的結構關係為:
在MFC編程式的過程中應該始終注意類間關係,類的種類和用途,以便找到適合的類來實現特定功能,就像本節在客戶區和非客戶區以及整個案頭繪圖一樣,不同的類有不同的特點。