一、概念
1. GDI:(Graphics Device Interfase)圖形設備接口,是一個應用程序與輸出設備之間的中介。
一方面,GDI向應用程序提供一個與設備無關的編程環境,另一方面,它又以設備相關的格式和具體的設備打交道。
2. DC:(Device Context)設備描述表,是一種Windows數據結構。包括了與一個設備的繪制屬性相關的信息。所有的繪制操作通過一個設備描述表進行,繪制線條、形狀和文本的Windows API 函數都與DC有關。
二、 在Windows Application程序中畫線
1. 定義兩個全局變量用於記錄鼠標按下的(x,y)坐標。
int nOrginX; int nOrginY;
2. 響應鼠標按下和鼠標抬起的消息:
在Swich中加入case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
3. 在鼠標按下時記錄鼠標按下的(x,y)坐標,查MSDN得知WM_LBUTTONDOWNlParam的低字存放x坐標,高字存放y坐標,將其取出存入nOrginX,nOrginY。
case WM_LBUTTONDOWN:
nOrginX=lParam & 0x0000ffff;
nOrginY=lParam >> 16 & 0x0000ffff;
break;
4. 在鼠標抬起時畫線:
case WM_LBUTTONUP:
HDC hdc;
hdc=GetDC(hwnd);
PAINTSTRUCT ps;
::MoveToEx(hdc,nOrginX,nOrginY,NULL);
::LineTo(hdc,LOWORD(lParam),HIWORD(lParam) );
::ReleaseDC(hwnd,hdc);
三、在MFC程序中畫線
1. 在CxxxView中響應鼠標按下和鼠標抬起的消息(因為只有CxxxView中才能接收到鼠標消息):
使用ClassWizard加入WM_LBUTTONDOWN,WM_LBUTTONUP的消息響應函數OnLButtonDown, OnLButtonUp。
2. 在CxxxView中添加成員變量CPoint m_ptOrigin,用於記錄鼠標按下的(x,y)坐標。
CPoint是一個用於描述點的簡單的類,它有兩個成員變量可以存放點的(x,y)坐標。
3. 在鼠標按下時記錄該點的坐標:
m_ptOrigin =point;
其中point是調用OnLButtonDown傳入的鼠標按下的點的坐標。
4. 在鼠標抬起時畫線:
CClientDC dc(this);
dc.MoveTo(m_ptOrigin); dc.LineTo(point);
其中CClientDC 是一個CDC的子類,在它的構造函數中調用了GetDC,析構函
數中調用了ReleaseDC,簡化了用戶的操作。
四、 實現橡皮筋功能
1.再定義一個成員變量,用於記錄鼠標抬起的點,以便擦線。
CPoint m_ptEnd;
2. 在鼠標按下時記錄該點的坐標:
m_ptOrigin=m_ptEnd=point;
3.使用ClassWizard加入WM_MOUSEMOVE的消息響應函數OnMouseMove。
在鼠標移動時判斷鼠標左鍵是否按下,如果按下,就不斷地擦去上一條線,畫出鼠標按下點到鼠標移動的當前點之間線。
if(MK_LBUTTON & nFlags)
{
CClientDC dc(this);
dc.SetROP2(R2_NOT);
dc.MoveTo(m_ptOrigin);
dc.LineTo(m_ptEnd);
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);
m_ptEnd=point;
}
其中:
if (MK_LBUTTON & nFlags) 是判斷鼠標左鍵是否按下。在調用OnMouseMove時,不僅為用戶傳來了坐標信息,還把鼠標左鍵是否按下,Shift鍵是否按下(詳細信息可查MSDN)等信息放在UINT nFlags中傳入OnMouseMove,用戶可以檢查相應位是否為1來判斷相應鍵是否按下。
dc.SetROP2(R2_NOT); 該句設置逆轉當前屏幕顏色的繪圖模式。這種模式下,在屏幕上首次畫出的線的是可見的,但在同一位置再畫一遍時,線就不見了。這樣可以方便的實現不斷畫線、擦線的效果。
五、 生成自定義的筆和刷子
1. Windows的GDI對象:CGDIObject
(1). CPen :用來畫線及繪制有形邊框的工具,可以指定它的顏色及寬度,並且可以指定它的線型(實線、點線、虛線等)。
(2).CBrush :對區域內部填充顏色。
(3).CFont :字體是一種具有某種風格和尺寸的所有字符的完整集合。
(4).CBitmap:位圖是一種位矩陣,每一個顯示象素都對應於其中的一個或多個位,可以利用位圖來表示圖象,也可以利用它來創建刷子。
(5).CRgn :區域是由多邊形、橢圓或二者組合形成的一種范圍,可以利用它來進行填充、裁剪以及點中測試。
當用戶生成一個GDI對象時,它是不會生效的。必須用SelectObject將該GDI對象選入設備描述表,它才會在以后的繪制操作中生效。SelectObject函數會返回指向前一次被選對象的指針。
2 自定義畫筆
CPen 類提供構造函數用於產生Cpen可以定義筆的線型、線寬和顏色。
CPen( int nPenStyle, int nWidth, COLORREF crColor );
程序中,生成了一個實線,寬度為6,顏色為黑色的筆。要注意的是,有的線型只在線寬小於1時才有效。
CPen newpen(PS_SOLID ,6,RGB(255,0,0));
dc.SelectObject(&newpen);
3 自定義刷子:
CBrush 提供用於產生刷子的構造函數:
CBrush( COLORREF crColor );
CBrush( int nIndex, COLORREF crColor );
CBrush( CBitmap* pBitmap );
(1). CBrush( COLORREF crColor );
它可以產生某種顏色的實心刷子,下面的代碼產生了一個紅色的實心刷子。
CBrush br(RGB(255,0,0));
dc.SelectObject(&br);
(2) CBrush( int nIndex, COLORREF crColor );
它可以產生某種剖面線的刷子,下面的代碼產生了一個紅色的剖面線刷子。 CBrush br(HS_FDIAGONAL,RGB(255,0,0));
dc.SelectObject(&br);
(3)CBrush( CBitmap* pBitmap );
它可以產生位圖刷子。
CBitmap bmp;
bmp.LoadBitmap(IDB_BITMAP1);
CBrush br(&bmp);
dc.SelectObject(&br);
這段代碼首先裝入了一幅位圖(先在資源中添加一個位圖資源,其ID指定為IDB_BITMAP1),再根據這幅位圖產生了一個位圖刷子。
六、繪圖操作
CDC類
在選擇了畫筆和刷子后就可以利用Windows的作圖函數進行作圖了
基本的畫線函數有以下幾種
CDC::MoveTo( int x, int y ); 改變當前點的位置 CDC::LineTo( int x, int y ); 畫一條由當前點到參數指定點的線 CDC::SetPixel(CPoint, CPen);畫點 CDC::BOOL Arc( LPCRECT lpRect, POINT ptStart, POINT ptEnd ); 畫弧線CDC::BOOL Polyline( LPPOINT lpPoints, int nCount ); 將多條線依次序連接 基本的作圖函數有以下幾種: CDC::BOOL Rectangle( LPCRECT lpRect ); 矩形 CDC::RoundRect( LPCRECT lpRect, POINT point ); 圓角矩形 CDC::Draw3dRect( int x, int y, int cx, int cy, COLORREF clrTopLeft, COLORREF clrBottomRight ); 3D邊框 CDC::Chord( LPCRECT lpRect, POINT ptStart, POINT ptEnd ); 扇形 CDC::Ellipse( LPCRECT lpRect ); 橢圓形 CDC::Pie( LPCRECT lpRect, POINT ptStart, POINT ptEnd ); CDC::Polygon( LPPOINT lpPoints, int nCount ); 多邊形。
對於矩形,圓形或類似的封閉曲線,系統會使用畫筆繪制邊緣,使用刷子填充內部。如果你不希望填充或是畫出邊緣,你可以選入空(NULL_PEN)筆或空(NULL_BRUSH)刷子。 在窗口中繪制設備相關位圖,圖標,設備無關位圖。
在Windows中可以將預先准備好的圖像復制到顯示區域中,這種內存拷貝執行起來是非常快的。在Windows中提供了兩種使用圖形拷貝的方法:通過設備相關位圖(DDB)和設備無關位圖(DIB)。DDB可以用MFC中的CBitmap來表示。通過CDC::BitBlt把內存中繪制圖形復制到屏幕上(StretchBlt可以進行縮放) 光柵操作的類型,可取以下值:
BLACKNESS 輸出區域為黑色 DSTINVERT 反色輸出區域
MERGECOPY 在源和目的間使用AND操作
MERGEPAINT 在反色后的目的和源間使用OR操作 NOTSRCCOPY 將反色后的源拷貝到目的區 PATINVERT 源和目的間進行XOR操作 SRCAND 源和目的間進行AND操作 SRCCOPY 復制源到目的區
SRCINVERT 源和目的間進行XOR操作 SRCPAINT 源和目的間進行OR操作 WHITENESS 輸出區域為白色 下面用代碼演示這種方法:
CXXXView::OnDraw(CDC* pDC)
{
CDC memDC;//定義一個兼容DC
memDC.CreateCompatibleDC(pDC);//創建DC
CBitmap bmpDraw;
bmpDraw.LoadBitmap(ID_BMP);//裝入DDB
CBitmap* pbmpOld=memDC.SelectObject(&bmpDraw);//保存原有DDB,並選入新DDB入DC pDC->BitBlt(0,0,20,20,&memDC,0,0,SRCCOPY);//將源DC中(0,0,20,20)復制到目的DC(0,0,20,20)
pDC->BitBlt(20,20,40,40,&memDC,0,0,SRCAND);//將源DC中(0,0,20,20)和目的DC(20,20,40,40)區域進行AND操作
memDC.SelectObject(pbmpOld);//選入原DDB
圖標的操作
CWinApp::LoadIcon( UINT nIDResource )或CWinApp::LoadStandardIcon( LPCTSTR lpszIconName ) 裝入,用CDC::DrawIcon繪制。用DestroyIconq清除圖標 設備無關位圖。
DIB操作
MFC沒有提供DIB操作的類,我們需要自己讀取位圖文件中的頭信息和數據,用StretchDIBits繪制。位圖文件結構 JPG PNP GIF
BITMAPFILEHEADER結構
BITMAPINFOHEADER結構
調色板信息
數據
多邊形和剪貼區域
CreateRectRgn 由矩形創建一個多邊形 CreateEllipticRgn 由橢圓創建一個多邊形
CreatePolygonRgn 創建一個有多個點圍成的多邊形 PtInRegion 某點是否在內部 CombineRgn 兩個多邊形相並
EqualRgn 兩個多邊形是否相等
Windows中的映射模式
1、Windows定義映射模式的目的,以下幾個方面:
a、不同人的使用習慣。不同國家的,不同地區,以及不同的人因為習慣喜歡用不同的度量單位,有的人人喜歡用英寸,而有的人喜歡用公制中的厘米,毫米等。其他的人又喜歡用另外一些單位。
b、使軟件與硬件向分離開來。讓開發的軟件能夠最大限度的與硬件無關。 c、提供邏輯和物理的一種轉換。就相當於銀行的利率。
2、默認的映射模式
默認的映射模式使MM_TEXT,它使以象素為單位的。X軸向左為正,Y軸向下為正。默認的坐標原點在左上角。
3、固定比例映射模式固定比例的映射模式有MM_LOMETRIC、MM_HIMETRIC、MM_LOENGLISH、MM_HIENGLISH、MM_TWIPS種。它們默認的坐標原點都使在左上角。其區別在於每一個邏輯單位對應的物理大小不一樣。所對用的邏輯單位分別為0.1毫米,0.01毫米,0.01英寸,0.001英寸,1/1440英寸(0.0007英寸)。
4、可變比例映射模式
對於可變比例的映射模式用戶可以自己定義一個邏輯單位代表的大小,其大小可以任意。也可以讓這個大小隨環境改變而改變。有MM_ISOTROPIC,MM_ANISOTROPIC這兩種映射模式。其邏輯單位的大小等於視口范圍和窗口范圍的比值。兩者的不同在於前者要求X軸和Y軸的度量單位必須相同,而后者沒有這樣的限制。
七、Windows中的幾種坐標體系
1、屏幕坐標
屏幕坐標描述物理設備(顯示器、打印機等)的一種坐標體系,坐標原點在屏幕的左上角,X軸向右為正,Y軸向下為正。度量單位是象素。原點、坐標軸方向、度量單位都是不能夠改變的。
2、設備坐標(又稱物理坐標)
設備坐標是描述在屏幕和打印機顯示或打印的窗體的一種坐標體系。默認的坐標原點是在其客戶區的左上角。X軸向右為正,Y軸向下為正。度量單位為象素。原點和坐標軸方向可以改變,但是度量單位不可以改變。
3、邏輯坐標
邏輯坐標是在程序中控制顯示,打印使用的坐標體系。該坐標系與定義的映射模式密切相關。默認的映射模式是MM_TEXT。我們可以通過設置不同的映射模式來改變該坐標體系的默認行為。
例:邏輯坐標和設備坐標之間的轉換
void CMapModeView::OnPaint()
{
CPaintDC dc(this);//獲取設備類的設置
CPoint ptOrgView,ptOrgWindow;
CSize sizeView,sizeWindow;
CString strMsg;
ptOrgView=dc.GetViewportOrg();//獲取視口原點
ptOrgWindow=dc.GetWindowOrg();//獲取窗口原點
sizeView=dc.GetViewportExt();//獲取視口范圍
sizeWindow=dc.GetWindowExt();//獲取窗口范圍
strMsg.Format(_T("Viewport Extent:(%d,%d),\tViewport Org:(%d,%d)\tWindow Extent:(%d,%d\tWindow Org(%d,%d)"),sizeView.cx,sizeView.cy,ptOrgView.x,ptOrgView.y,sizeWindow.cx,sizeWindow.cy,ptOrgWindow.x,ptOrgWindow.y); TRACE("%s\n",strMsg); //設置映射模式以及原點
dc.SetMapMode(MM_TEXT);//設置映射模式
dc.SetWindowOrg(100,100);//設置窗口的坐標原點
dc.SetViewportOrg(200,200);//設置視口的坐標原點
dc.SetWindowExt(5,10);//改語句僅對可變比例映射模式有效
dc.SetViewportExt(1,1);
ptOrgView=dc.GetViewportOrg();
ptOrgWindow=dc.GetWindowOrg();
sizeView=dc.GetViewportExt();
sizeWindow=dc.GetWindowExt();
strMsg.Format(_T("Viewport Extent:(%d,%d),\tViewport Org:(%d,%d)\tWindow Extent:(%d,%d)\tWindow Org(%d%d)"),sizeView.cx,sizeView.cy,ptOrgView.x,ptOrgView.y,sizeWindow.cx,sizeWindow.cy,ptOrgWindow.x,ptOrgWindow.y);
TRACE("%s\n",strMsg);
//將點(300,400)從邏輯坐標體系映射到設備坐標體系。
CPoint ptMap;
ptMap=CPoint(300,400);
dc.LPtoDP(&ptMap);
strMsg.Format(_T("The Orginal Point(In LP):CPoint(300,400),Convert to DP is:CPoint(%d,%d)"), ptMap.x,ptMap.y);
TRACE("%s\n",strMsg);
//將點(300,400)從設備坐標體系映射到邏輯坐標體系 ptMap=CPoint(300,400); dc.DPtoLP(&ptMap);
strMsg.Format(_T("The Orginal Point(In DP):CPoint(300,400),Convert to LP is:CPoint(%d%d)"), ptMap.x,ptMap.y);
TRACE("%s\n",strMsg);
}
發布於CSDN: 2015-05-11
