|
5.清屏 Windows沒有提供專門的清屏函數(shù),可以調(diào)用CWnd的下面兩個函數(shù)調(diào)用來完成該功能: void Invalidate(BOOL bErase = TRUE); void UpdateWindow( ); 或調(diào)用CWnd的函數(shù) BOOL RedrawWindow( LPCRECT lpRectUpdate = NULL, CRgn* prgnUpdate = NULL, UINT flags = RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASE ); 來完成。 例如(菜單項(xiàng)ID_CLEAR的事件處理函數(shù)): CDrawView::On //Invalidate(); //UpdateWindow( ); RedrawWindow( ); } 也可以用畫填充背景色矩形的方法來清屏,如: RECT rect; GetClientRect(&rect); pDC->FillSolidRect(&rect, RGB(255, 255, 255)); 6.在控件上繪圖 可以在對話框資源中放置圖片控件,并對其類型屬性選Frame??稍趯υ捒虻睦L圖消息響應(yīng)函數(shù)On CWnd* GetDlgItem( int nID ) const; 來獲得圖片控件的窗口對象,再用函數(shù)GetDC: CDC* GetDC( ); 由窗口對象得到DC,然后就可以用該DC在控件中畫圖。如(在ID為IDC_HUESAT的圖片控件上畫調(diào)色板) void CColorDlg::On { if (IsIconic()) { ... ... } else { CDialog::On int i, j; BYTE r, g, b; // get control window and DC of Hue&Saturation CWnd *pWin = GetDlgItem(IDC_HUESAT); CDC *pDC = pWin->GetDC(); // draw hue-saturation palette for (i = 0; i < 360; i++) for (j = 0; j <= 255; j++) { HSLtoRGB(i, 255 - j, 128, r, g, b); // 自定義函數(shù),見網(wǎng)絡(luò)硬盤的 // res目錄中的ColTrans.cpp文件 pDC->SetPixel(i, j, RGB(r, g, b)); } ... ... } } 在非Frame類靜態(tài)控件上繪圖,必須先按順序依次調(diào)用CWnd類的Invalidate和UpdateWindow函數(shù)后,再開始用DC畫圖。如在一個ID為IDC_COLOR的按鈕上繪圖: void CComDlgDlg::DrawColor() { CWnd* pWnd = GetDlgItem(IDC_COLOR); CDC* pDC = pWnd->GetDC(); CRect rect; pWnd->GetClientRect(&rect); pWnd->Invalidate(); pWnd->UpdateWindow(); pDC->FillRect(&rect, new CBrush(m_crCol)); } 若干說明: <!--[if !supportLists]-->l <!--[endif]-->除了基于對話框的程序外,其他對話框類都需要自己添加(重寫型)消息響應(yīng)函數(shù)On <!--[if !supportLists]-->l <!--[endif]-->為了使在運(yùn)行時能夠不斷及時更新控件的顯示(主要是自己加的顯式代碼),可以將自己繪制控件的所有代碼都全部加入對話框類的消息響應(yīng)函數(shù)On <!--[if !supportLists]-->l <!--[endif]-->一般的對話框類,缺省時都沒有明寫出On <!--[if !supportLists]-->l <!--[endif]-->為了在鼠標(biāo)指向按鈕時,讓按鈕上自己繪制的圖形不被消去,可以設(shè)置按鈕控件的“Owner Draw”屬性為“True”。 <!--[if !supportLists]-->l <!--[endif]-->如果希望非按鈕控件(如圖片控件和靜態(tài)文本等),也可以響應(yīng)鼠標(biāo)消息(如單擊、雙擊等),需要設(shè)置控件的“Notify”屬性為“True”。 <!--[if !supportLists]-->l <!--[endif]-->使用On //CDialog::On <!--[if !supportLists]-->l <!--[endif]-->對話框的背景色,可以用CWnd類的成員函數(shù): DWORD GetSysColor( int nIndex); 得到,其中的nIndex取為COLOR_BTNFACE。例如: dc.SetBkColor(GetSysColor(COLOR_BTNFACE)); 下面是部分例子代碼:(其中FillColor和ShowImg為自定義的成員函數(shù)) void CSetDlg::On { // TODO: 在此添加控件通知處理程序代碼 CColorDialog colDlg(m_crLineColor); if (colDlg.DoModal() == IDOK) { m_crLineColor = colDlg.GetColor(); Invalidate(); UpdateWindow(); } } // …… void CSetDlg::On { CPaintDC dc(this); // device context for painting // TODO: 在此處添加消息處理程序代碼 // 不為繪圖消息調(diào)用 CDialog::On FillColor(IDC_PEN_COLOR, m_crLineColor); FillColor(IDC_BRUSH_COLOR, m_crBrushColor); if(m_pBitmap0 != NULL) ShowImg(IDC_BRUSH_IMG, m_hBmp0); else if(m_pBitmap != NULL) ShowImg(IDC_BRUSH_IMG, m_hBmp); } void CSetDlg::FillColor(UINT id, COLORREF col) { CWnd* pWnd = GetDlgItem(id); CDC* pDC = pWnd->GetDC(); pDC->SelectObject(new CPen(PS_SOLID, 1, RGB(0, 0, 0))); pDC->SelectObject(new CBrush(col)); CRect rect; pWnd->GetClientRect(&rect); pWnd->Invalidate(); pWnd->UpdateWindow(); pDC->RoundRect(&rect, CPoint(8, 8)); } void CSetDlg::ShowImg(UINT ID, HBITMAP hBmp) { CWnd* pWnd = GetDlgItem(ID); CDC* pDC = pWnd->GetDC(); CRect rect; pWnd->GetClientRect(&rect); pWnd->Invalidate(); pWnd->UpdateWindow(); BITMAP bs; GetObject(hBmp, sizeof(bs), &bs); CDC dc; if(dc.CreateCompatibleDC(pDC)) { int x0, y0, w, h; float rx = (float)bs.bmWidth / rect.right, ry = (float)bs.bmHeight / rect.bottom; if (rx >= ry) { x0 = 0; w = rect.right; h = (int)(bs.bmHeight / rx + 0.5); y0 = (rect.bottom - h) / 2; } else { y0 = 0; h = rect.bottom; w = (int)(bs.bmWidth / ry + 0.5); x0 = (rect.right - w) / 2; } ::SelectObject(dc.GetSafeHdc(), hBmp); pDC->SetStretchBltMode(HALFTONE); pDC->StretchBlt(x0, y0, w, h, &dc, 0, 0, bs.bmWidth, bs.bmHeight, SRCCOPY); SetDlgItemInt(IDC_W, bs.bmWidth); SetDlgItemInt(IDC_H, bs.bmHeight); } } //…… 5 設(shè)置繪圖屬性 除了映射模式外,還有許多繪圖屬性可以設(shè)置,如背景、繪圖方式、多邊形填充方式、畫弧方向、刷原點(diǎn)等。 1.背景 1)背景色 當(dāng)背景模式為不透明時,背景色決定線狀圖的空隙顏色(如虛線中的空隙、條紋刷的空隙和文字的空隙),可以使用CDC類的成員函數(shù)GetBkColor和SetBkColor來獲得和設(shè)置當(dāng)前的背景顏色: COLORREF GetBkColor( ) const; // 返回當(dāng)前的背景色 virtual COLORREF SetBkColor( COLORREF crColor ); // 返回先前的背景色 // 若出錯返回0x80000000 2)背景模式 背景模式影響有空隙的線狀圖的空隙(如虛線中的空隙、條紋刷的空隙和文字的空隙)用什么辦法填充??梢允褂肅DC類的成員函數(shù)GetBkMode和SetBkMode來獲得和設(shè)置當(dāng)前的背景模式: int GetBkMode( ) const; // 返回當(dāng)前背景模式 int SetBkMode( int nBkMode ); // 返回先前背景模式 背景模式的取值 nBkMode值 名稱 作用 OPAQUE 不透明的(缺省值) 空隙用背景色填充 TRANSPARENT 透明的 空隙處保持原背景圖不變 2. 繪圖模式 繪圖模式(drawing mode)指前景色的混合方式,它決定新畫圖的筆和刷的顏色(pbCol)如何與原有圖的顏色(scCol)相結(jié)合而得到結(jié)果像素色(pixel)。 1)設(shè)置繪圖模式 可使用CDC類的成員函數(shù)SetROP2 (ROP = Raster OPeration光柵操作)來設(shè)置繪圖模式: int SetROP2( int nDrawMode ); 其中,nDrawMode可取值: 繪圖模式nDrawMode的取值 符號常量 作用 運(yùn)算結(jié)果 R2_BLACK 黑色 pixel = black R2_WHITE 白色 pixel = white R2_NOP 不變 pixel = scCol R2_NOT 反色 pixel = ~scCol R2_COPYPEN 覆蓋 pixel = pbCol R2_NOTCOPYPEN 反色覆蓋 pixel = ~pbCol R2_MERGEPENNOT 反色或 pixel = ~scCol | pbCol R2_MERGENOTPEN 或反色 pixel = scCol | ~pbCol R2_MASKNOTPEN 與反色 pixel = scCol & ~pbCol R2_MERGEPEN 或 pixel = scCol | pbCol R2_NOTMERGEPEN 或非 pixel = ~(scCol | pbCol) R2_MASKPEN 與 pixel = scCol & pbCol R2_NOTMASKPEN 與非 pixel = ~(scCol & pbCol) R2_XORPEN 異或 pixel = scCol ^ pbCol R2_NOTXORPEN 異或非 pixel = ~(scCol ^ pbCol) 其中,R2_COPYPEN(覆蓋)為缺省繪圖模式,R2_XORPEN(異或)較常用。 2)畫移動圖形 為了能畫移動的位置標(biāo)識(如十字、一字)和隨鼠標(biāo)移動畫動態(tài)圖形(如直線、矩形、橢圓),必須在不破壞原有背景圖形的基礎(chǔ)上移動這些圖形。 移動圖形采用的是異或畫圖方法,移動圖形的過程為:異或畫圖、在原位置再異或化圖(擦除)、在新位置異或畫圖、……。 如 pGrayPen = new CPen(PS_DOT, 0, RGB(128, 128, 128)); pDC->SetBkMode(TRANSPARENT); pOldPen = pDC->SelectObject(pGrayPen); pDC->SelectStockObject(NULL_BRUSH); pDC->SetROP2(R2_XORPEN); if (m_bErase) pDC->Ellipse(rect0); pDC->Ellipse(rect); pDC->SetROP2(R2_COPYPEN); pDC->SelectObject(pOldPen); rect0 = rect; 較完整的拖放動態(tài)畫圖的例子,可參照下面的“3. 拖放畫動態(tài)直線”部分。 3)其他屬性 <!--[if !supportLists]-->l <!--[endif]-->多邊形填充方式:可使用CDC類的成員函數(shù)GetPolyFillMode和SetPolyFillMode來確定多邊形的填充方式: int GetPolyFillMode( ) const; int SetPolyFillMode( int nPolyFillMode ); 其中nPolyFillMode 可取值A(chǔ)LTERNATE(交替——填充奇數(shù)邊和偶數(shù)邊之間的區(qū)域,缺省值)或WINDING(纏繞——根據(jù)多邊形邊的走向來確定是否填充一區(qū)域) <!--[if !supportLists]-->l <!--[endif]-->畫弧方向:可使用CDC類的成員函數(shù)GetArcDirection和SetArcDirection來確定Arc、Chord、Pie等函數(shù)的畫弧方向: int GetArcDirection( ) const; int SetArcDirection( int nArcDirection ); 其中,nArcDirection可取值A(chǔ)D_COUNTERCLOCKWISE(逆時針方向,缺省值)和AD_CLOCKWISE(順時針方向) <!--[if !supportLists]-->l <!--[endif]-->刷原點(diǎn):可使用CDC類的成員函數(shù)GetBrushOrg和SetBrushOrg來確定可填充繪圖函數(shù)的條紋或圖案刷的起點(diǎn):(缺省值為客戶區(qū)左上角的坐標(biāo)原點(diǎn)(0, 0)) CPoint GetBrushOrg( ) const; CPoint SetBrushOrg( int x, int y ); CPoint SetBrushOrg( POINT point ); 3.拖放畫動態(tài)直線 下面是一個較完整的拖放動態(tài)畫直線的例子: // 類變量 class CDrawView : public CView { //…… protected: BOOL m_bLButtonDown, m_bErase; // 判斷是否按下左鼠標(biāo)鍵 //和是否需要擦除圖形的類變量 CPoint p0, pm; // 記錄直線起點(diǎn)和動態(tài)終點(diǎn)的類變量 CPen * pGrayPen, * pLinePen; // 定義灰色和直線筆 //…… } // 構(gòu)造函數(shù) CDrawView::CDrawView() { m_bLButtonDown = FALSE; // 設(shè)左鼠標(biāo)鍵按下為假 m_bErase = FALSE; // 設(shè)需要擦除為假 pGrayPen = new CPen(PS_SOLID, 0, RGB(128, 128, 128));// 創(chuàng)建灰色筆 pLinePen = new CPen(PS_SOLID, 0, RGB(255, 0, 0));// 創(chuàng)建紅色的直線筆 } // 鼠標(biāo)消息響應(yīng)函數(shù) void CDrawView::On m_bLButtonDown = TRUE; // 設(shè)左鼠標(biāo)鍵按下為真 SetCapture(); // 設(shè)置鼠標(biāo)捕獲 // SetCursor(LoadCursor(NULL, IDC_CROSS)); // 設(shè)置鼠標(biāo)為十字 p0 = point; // 保存矩形左上角 pm = p0; // 讓矩形右下角等于左上角 CView::On } void CDrawView::On SetCursor(LoadCursor(NULL, IDC_CROSS)); // 設(shè)置鼠標(biāo)為十字 if (m_bLButtonDown) { // 左鼠標(biāo)鍵按下為真 CDC* pDC = GetDC(); // 獲取設(shè)備上下文 pDC->SelectObject(pGrayPen);// 選取灰色筆 pDC->SetROP2(R2_XORPEN);// 設(shè)置為異或繪圖方式 if (m_bErase) { // 需要擦除為真 pDC->MoveTo(p0); pDC->LineTo(pm); // 擦除原直線 } else // 需要擦除為假 m_bErase = TRUE; // 設(shè)需要擦除為真 pDC->MoveTo(p0); pDC->LineTo(point); // 繪制新直線 pm = point; // 記錄老終點(diǎn) ReleaseDC(pDC); // 釋放設(shè)備上下文 } CView::On } void CDrawView::On ReleaseCapture(); // 釋放鼠標(biāo)捕獲 if (m_bLButtonDown) { // 左鼠標(biāo)鍵按下為真 CDC* pDC = GetDC(); // 獲取設(shè)備上下文 pDC->SelectObject(pGrayPen);// 選取灰色筆 pDC->SetROP2(R2_XORPEN); // 設(shè)置為異或繪圖方式 pDC->MoveTo(p0); pDC->LineTo(pm); // 擦除原直線 pDC->SelectObject(pLinePen); // 選擇直線筆 pDC->SetROP2(R2_COPYPEN);// 設(shè)置為覆蓋繪圖方式 pDC->MoveTo(p0); pDC->LineTo(point); // 繪制最終的直線 m_bLButtonDown = FALSE; // 重設(shè)左鼠標(biāo)鍵按下為假 m_bErase = FALSE; // 重需要擦除為假 ReleaseDC(pDC); // 釋放設(shè)備上下文 } CView::On } |
|
|