• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            mfc繪圖(轉(zhuǎn)載)

            4 畫圖
            在Windows中,繪圖一般在視圖窗口的客戶區(qū)進(jìn)行,使用的是設(shè)備上下文類CDC中各種繪圖函數(shù)。
            1. 映射模式與坐標(biāo)系
            1)默認(rèn)映射模式
            映射模式(map mode)影響所有的圖形和文本繪制函數(shù),它定義(將邏輯單位轉(zhuǎn)換為設(shè)備單位所使用的)度量單位和坐標(biāo)方向,Windows總是用邏輯單位來繪圖。
            缺省情況下,繪圖的默認(rèn)映射模式為MM_TEXT,其繪圖單位為像素(只要不打印輸出,屏幕繪圖使用該模式就夠了)。若窗口客戶區(qū)的寬和高分別為w和h像素,則其x坐標(biāo)是從左到右,范圍為0 ~ w-1;y坐標(biāo)是從上到下,范圍為0 ~ h-1。

            2)設(shè)置映射模式
            可以使用CDC類的成員函數(shù)GetMapMode和SetMapMode來獲得和設(shè)置當(dāng)前的映射模式:
            int GetMapMode( ) const; // 返回當(dāng)前的映射模式
            virtual int SetMapMode( int nMapMode ); // 返回先前的映射模式


            映射模式的nMapMode取值與含義
            符號(hào)常量 數(shù)字常量 x方向 y方向 邏輯單位的大小 
            MM_TEXT 1 向右 向下 像素 
            MM_LOMETRIC 2 向右 向上 0.1 mm 
            MM_HIMETRIC 3 向右 向上 0.01 mm 
            MM_LOENGLISH 4 向右 向上 0.01 in 
            MM_HIENGLISH 5 向右 向上 0.001 in 
            MM_TWIPS 6 向右 向上 1/1440 in 
            MM_ISOTROPIC 7 自定義 自定義 自定義 
            MM_ANISOTROPIC 8 自定義 自定義 自定義


            可見,除了兩種自定義映射模式外,x方向都是向右,y方向也只有MM_TEXT的向下,其余的都是向上,與數(shù)學(xué)上一致。除了MM_ANISOTROPIC外,其他所有映射模式的x與y方向的單位都是相同的。所有映射模式的邏輯坐標(biāo)的原點(diǎn)(0, 0)最初都是在窗口的左上角,但在CScrollView的派生類中,MFC會(huì)隨用戶滾動(dòng)文檔而自動(dòng)調(diào)整邏輯原點(diǎn)的相對(duì)位置(改變視點(diǎn)的原點(diǎn)屬性)。
            3)自定義映射模式
            自定義映射模式MM_ISOTROPIC(各向同性,x與y方向的單位必須相同)和MM_ANISOTROPIC(各向異性,x與y方向的單位可以不同)的單位和方向,可以通過用CDC類的成員函數(shù)G/SetWindowExt和G/SetViewportExt來獲取/設(shè)置窗口和視口的大小來確定:
            CSize GetWindowExt( ) const;
            virtual CSize SetWindowExt( int cx, int cy );

            virtual CSize SetWindowExt( SIZE size );
            CSize GetViewportExt( ) const;
            virtual CSize SetViewportExt( int cx, int cy );

            virtual CSize SetViewportExt( SIZE size );
            其中,cx或size.cx和cy或size.cy分別為窗口/視口的寬度與高度(邏輯單位)。
            還可以用CDC類的成員函數(shù)SetViewportOrg來設(shè)置坐標(biāo)原點(diǎn)的位置:
            virtual CPoint SetViewportOrg( int x, int y );
            CPoint SetViewportOrg( POINT point );
            例如
            void CDrawView::OnDraw(CDC* pDC) {
                   CRect rect;
                   GetClientRect(rect);
                   pDC->SetMapMode(MM_ANISOTROPIC);
                   pDC->SetWindowExt(1000,1000);
                   pDC->SetViewportExt(rect.right, -rect.bottom);

                   pDC->SetViewportOrg(rect.right / 2, rect.bottom /2);

                   pDC->Ellipse(CRect(-500, -500, 500, 500));

            }
            將當(dāng)前的映射模式設(shè)置為各向異性自定義映射模式,窗口大小為1000個(gè)邏輯單位寬和1000個(gè)邏輯單位高,視口大小同當(dāng)前客戶區(qū),視口的坐標(biāo)原點(diǎn)設(shè)置在當(dāng)前客戶區(qū)的中央。由于使用了負(fù)數(shù)作為SetViewportExt函數(shù)的第2個(gè)參數(shù),所以y軸方向是向上的。

            可見,圓被畫成了橢圓,x與y方向上的邏輯單位不相同。
            4)單位轉(zhuǎn)換
            對(duì)所有非MM_TEXT映射模式,有如下重要規(guī)則:
            <!--[if !supportLists]-->l         <!--[endif]-->CDC的成員函數(shù)(如各種繪圖函數(shù))具有邏輯坐標(biāo)參數(shù)

            <!--[if !supportLists]-->l         <!--[endif]-->CWnd的成員函數(shù)(如各種響應(yīng)函數(shù))具有設(shè)備坐標(biāo)參數(shù)(如鼠標(biāo)位置point)

            <!--[if !supportLists]-->l         <!--[endif]-->位置的測(cè)試操作(如CRect的PtInRect函數(shù))只有使用設(shè)備坐標(biāo)時(shí)才有效

            <!--[if !supportLists]-->l         <!--[endif]-->長(zhǎng)期使用的值應(yīng)該用邏輯坐標(biāo)保存(如窗口滾動(dòng)后保存的設(shè)備坐標(biāo)就無效了)


            因此,為了使應(yīng)用程序能夠正確工作,除MM_TEXT映射模式外,其他映射模式都需要進(jìn)行單位轉(zhuǎn)換。下面是邏輯單位到設(shè)備單位(如像素)的轉(zhuǎn)換公式:
            x比例因子 = 視口寬度 / 窗口寬度
            y比例因子 = 視口高度 / 窗口高度
            設(shè)備x = 邏輯x * x比例因子 + x原點(diǎn)偏移量
            設(shè)備y = 邏輯y * y比例因子 + y原點(diǎn)偏移量
            Windows的GDI負(fù)責(zé)邏輯坐標(biāo)和設(shè)備坐標(biāo)之間的轉(zhuǎn)換,這可以調(diào)用CDC類的成員函數(shù)LPtoDP和DPtoLP來進(jìn)行:
            void LPtoDP( LPPOINT lpPoints, int nCount = 1 ) const;

            void LPtoDP( LPRECT lpRect ) const;
            void LPtoDP( LPSIZE lpSize ) const;
            void DPtoLP( LPPOINT lpPoints, int nCount = 1 ) const;

            void DPtoLP( LPRECT lpRect ) const;
            void DPtoLP( LPSIZE lpSize ) const;
            例如:
            void CDrawView::OnLButtonDown(UINT nFlags, CPoint point) {

                          CRect rect = m_rect; // 邏輯坐標(biāo)

                          CClientDC dc(this);
                          dc.SetMapMode(MM_LOENGLISH);
                          dc.LPtoDP(rect); // 轉(zhuǎn)化成設(shè)備坐標(biāo)
                   if (rect.PtInRect(point)) // 位置的測(cè)試操作只有使用設(shè)備坐標(biāo)時(shí)才有效

                   ......
            }
            void CDrawView:: OnMouseMove (UINT nFlags, CPoint point) {

                   float t,y;

                          char buf[40];
                   CDC* pDC = GetDC();

            pDC->SetMapMode(MM_HIMETRIC);
                          pDC->DPtoLP(&point); // 轉(zhuǎn)化成邏輯坐標(biāo)
            t = t1 + (point.x * dt) / w; sprintf(buf, "%.4fs", t); pSB->SetPaneText(xV, buf);

            y = (y0 - point.y) / dy; sprintf(buf, "%.4f", y); pSB->SetPaneText(yV, buf);
                   ......
            }
            2. 畫像素點(diǎn)
            畫像素點(diǎn)就是設(shè)置像素點(diǎn)的顏色,從前面3)(2)已知道這可由CDC的成員函數(shù)SetPixel來做,該函數(shù)的原型為:
            COLORREF SetPixel( int x, int y, COLORREF crColor ); 或

            COLORREF SetPixel( POINT point, COLORREF crColor );

            其中,x與y分別為像素點(diǎn)的橫坐標(biāo)與縱坐標(biāo),crColor為像素的顏色值。例如
            pDC->SetPixel(i, j, RGB(r, g, b));

            3.畫線狀圖
            在Windows中,線狀圖必須用筆來畫(筆的創(chuàng)建與使用見前面的3)(3)),下面是CDC類中可以繪制線狀圖的常用成員函數(shù):
            <!--[if !supportLists]-->l         <!--[endif]-->當(dāng)前位置:設(shè)置當(dāng)前位置為(x, y)或point:(返回值為原當(dāng)前位置的坐標(biāo))

            CPoint MoveTo( int x, int y ); 或 CPoint MoveTo( POINT point );

            <!--[if !supportLists]-->l         <!--[endif]-->畫線:使用DC中的筆從當(dāng)前位置畫線到點(diǎn)(x, y)或point:(若成功返回非0值):

            BOOL LineTo( int x, int y ); 或BOOL LineTo( POINT point );
            <!--[if !supportLists]-->l         <!--[endif]-->畫折線:使用DC中的筆,依次將點(diǎn)數(shù)組lpPoints中的nCount(≥2)個(gè)點(diǎn)連接起來,形成一條折線:

            BOOL Polyline( LPPOINT lpPoints, int nCount );
            <!--[if !supportLists]-->l         <!--[endif]-->畫多邊形:似畫折線,但還會(huì)將最后的點(diǎn)與第一個(gè)點(diǎn)相連形成多邊形,并用DC中的刷填充其內(nèi)部區(qū)域:

            BOOL Polygon( LPPOINT lpPoints, int nCount );
            <!--[if !supportLists]-->l         <!--[endif]-->畫矩形:使用DC中的筆畫左上角為(x1, y1)、右下角為(x2, y2)或范圍為*lpRect的矩形的邊線,并用DC中的刷填充其內(nèi)部區(qū)域:

            BOOL Rectangle( int x1, int y1, int x2, int y2 ); 或
            BOOL Rectangle( LPCRECT lpRect );
                          有時(shí)需要根據(jù)用戶給定的兩個(gè)任意點(diǎn)來重新構(gòu)造左上角和右下角的點(diǎn),例如:
                          rect = CRect(min(p0.x, point.x), min(p0.y, point.y), max(p0.x, point.x), max(p0.y, point.y));

            <!--[if !supportLists]-->l         <!--[endif]-->畫圓角矩形:使用DC中的筆畫左上角為(x1, y1)、右下角為(x2, y2)或范圍為*lpRect的矩形的邊線,并用寬x3或point.x高y3或point.y矩形的內(nèi)接橢圓倒角,再用DC中的刷填充其內(nèi)部區(qū)域:

            BOOL RoundRect( int x1, int y1, int x2, int y2, int x3, int y3 );
            BOOL RoundRect( LPCRECT lpRect, POINT point );
            例如:
            int d = min(rect.Width(), rect.Height()) / 4;

            pDC-> RoundRect(rect, CPoint(d, d));
            <!--[if !supportLists]-->l         <!--[endif]-->畫(橢)圓:使用DC中的筆在左上角為(x1, y1)、右下角為(x2, y2)或范圍為*lpRect的矩形中畫內(nèi)接(橢)圓的邊線,并用DC中的刷填充其內(nèi)部區(qū)域:

            BOOL Ellipse( int x1, int y1, int x2, int y2 );
            BOOL Ellipse( LPCRECT lpRect );
            注意,CDC中沒有畫圓的專用函數(shù)。在這里,圓是作為橢圓的(寬高相等)特例來畫的。
            <!--[if !supportLists]-->l         <!--[endif]-->畫弧:(x1, y1)與(x2, y2)或lpRect的含義同畫(橢)圓,(x3, y3)或ptStart為弧的起點(diǎn),(x4, y4)或ptEnd為弧的終點(diǎn):(逆時(shí)針方向旋轉(zhuǎn))

            BOOL Arc( int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4 );

            BOOL Arc( LPCRECT lpRect, POINT ptStart, POINT ptEnd );
            BOOL ArcTo(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4);

            BOOL ArcTo(LPCRECT lpRect, POINT ptStart, POINT ptEnd);
            畫圓弧:(其中(x, y)為圓心、nRadius為半徑、fStartAngle為起始角、fSweepAngle為弧段跨角)
            BOOL AngleArc(int x, int y, int nRadius, float fStartAngle, float fSweepAngle);

            <!--[if !supportLists]-->l         <!--[endif]-->畫弓弦:參數(shù)的含義同上,只是用一根弦連接弧的起點(diǎn)和終點(diǎn),形成一個(gè)弓形,并用DC中的刷填充其內(nèi)部區(qū)域:

            BOOL Chord( int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4 );

            BOOL Chord( LPCRECT lpRect, POINT ptStart, POINT ptEnd );
            4.畫填充圖
            在Windows中,面狀圖必須用刷來填充(刷的創(chuàng)建與使用見前面的3)(4))。上面(2)中的Polygon、Rectangle、Ellipse和Chord等畫閉合線狀圖的函數(shù),只要DC中的刷不是空刷,都可以用來畫對(duì)應(yīng)的面狀圖(邊線用當(dāng)前筆畫,內(nèi)部用當(dāng)前刷填充)。下面介紹的是CDC類中只能繪制面狀圖的其他常用成員函數(shù):
            <!--[if !supportLists]-->l         <!--[endif]-->畫填充矩形:用指定的刷pBrush畫一個(gè)以lpRect為區(qū)域的填充矩形,無邊線,填充區(qū)域包括矩形的左邊界和上邊界,但不包括矩形的右邊界和下邊界:

            void FillRect( LPCRECT lpRect, CBrush* pBrush );
            <!--[if !supportLists]-->l         <!--[endif]-->畫單色填充矩形:似FillRect,但只能填充單色,不能填充條紋和圖案:

            void FillSolidRect( LPCRECT lpRect, COLORREF clr );
            void FillSolidRect( int x, int y, int cx, int cy, COLORREF clr );
            <!--[if !supportLists]-->l         <!--[endif]-->畫餅圖(扇形):參數(shù)含義同Arc,但將起點(diǎn)和終點(diǎn)都與外接矩形的中心相連接,形成一個(gè)扇形區(qū)域,用DC中的刷填充整個(gè)扇形區(qū)域,無另外的邊線:

            BOOL Pie( int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4 );

            BOOL Pie( LPCRECT lpRect, POINT ptStart, POINT ptEnd );
            <!--[if !supportLists]-->l         <!--[endif]-->畫拖動(dòng)的矩形:先擦除線寬為sizeLast、填充刷為pBrushLast的原矩形lpRectLast,然后再以線寬為size、填充刷為pBrush畫新矩形lpRectLast。矩形的邊框用灰色的點(diǎn)虛線畫,缺省的填充刷為空刷:

            void DrawDragRect( LPCRECT lpRect, SIZE size, LPCRECT lpRectLast,

            SIZE sizeLast, CBrush* pBrush = NULL, CBrush* pBrushLast = NULL );

            如:pDC->DrawDragRect(rect, size, rect0, size);

            <!--[if !supportLists]-->l         <!--[endif]-->填充區(qū)域:

            <!--[if !supportLists]-->n     <!--[endif]-->用當(dāng)前刷從點(diǎn)(x, y)開始向四周填充到顏色為crColor的邊界:

            BOOL FloodFill(int x, int y, COLORREF crColor); // 成功返回非0

            <!--[if !supportLists]-->n     <!--[endif]-->用當(dāng)前刷從點(diǎn)(x, y)開始向四周填充:

            BOOL ExtFloodFill(int x, int y, COLORREF crColor,

            UINT nFillType); // 成功返回非0

            <!--[if !supportLists]-->u <!--[endif]-->nFillType = FLOODFILLBORDER:填充到顏色為crColor的邊界(同F(xiàn)loodFill);(用于填充內(nèi)部顏色不同但邊界顏色相同的區(qū)域)
            <!--[if !supportLists]-->u <!--[endif]-->nFillType = FLOODFILLSURFACE:填充所有顏色為crColor的點(diǎn),直到碰到非crColor顏色的點(diǎn)為止。(點(diǎn)(x, y)的顏色也必須為crColor),(用于填充內(nèi)部顏色相同但邊界顏色可以不同的區(qū)域)。例如:
            pDC->ExtFloodFill(point.x, point.y, pDC->GetPixel(point), FLOODFILLSURFACE);

            5.清屏
            Windows沒有提供專門的清屏函數(shù),可以調(diào)用CWnd的下面兩個(gè)函數(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::OnClear() { // 調(diào)用OnDraw來清屏
                   //Invalidate();
                   //UpdateWindow( );
                   RedrawWindow( );
            }
            也可以用畫填充背景色矩形的方法來清屏,如:
                   RECT rect;
                   GetClientRect(&rect);
                   pDC->FillSolidRect(&rect, RGB(255, 255, 255));

            6.在控件上繪圖
            可以在對(duì)話框資源中放置圖片控件,并對(duì)其類型屬性選Frame。可在對(duì)話框的繪圖消息響應(yīng)函數(shù)OnPaint或其他函數(shù)中,用CWnd類的函數(shù)GetDlgItem:
            CWnd* GetDlgItem( int nID ) const;
            來獲得圖片控件的窗口對(duì)象,再用函數(shù)GetDC:
            CDC* GetDC( );

            由窗口對(duì)象得到DC,然后就可以用該DC在控件中畫圖。如(在ID為IDC_HUESAT的圖片控件上畫調(diào)色板)
            void CColorDlg::OnPaint() 
            {
                   if (IsIconic()) {
                          ... ...
                   }
                   else {
                          CDialog::OnPaint();
                          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畫圖。如在一個(gè)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]-->除了基于對(duì)話框的程序外,其他對(duì)話框類都需要自己添加(重寫型)消息響應(yīng)函數(shù)OnInitDialog,來做一些必要的初始化對(duì)話框的工作。添加方法是:先在項(xiàng)目區(qū)選中“類視圖”頁(yè),再選中對(duì)應(yīng)的對(duì)話框類,然后在屬性窗口的“重寫”頁(yè)中添加該函數(shù);

            <!--[if !supportLists]-->l     <!--[endif]-->為了使在運(yùn)行時(shí)能夠不斷及時(shí)更新控件的顯示(主要是自己加的顯式代碼),可以將自己繪制控件的所有代碼都全部加入對(duì)話框類的消息響應(yīng)函數(shù)OnPaint中。在需要時(shí)(例如在繪圖參數(shù)修改后),自己調(diào)用CWnd的Invalidate和UpdateWindow函數(shù),請(qǐng)求系統(tǒng)刷新對(duì)話框和控件的顯示。因?yàn)榭丶彩谴翱冢丶惗际荂Wnd的派生類。所以在對(duì)話框和控件中,可以像在視圖類中一樣,調(diào)用各種CWnd的成員函數(shù)。

            <!--[if !supportLists]-->l     <!--[endif]-->一般的對(duì)話框類,缺省時(shí)都沒有明寫出OnPaint函數(shù)。可以自己在對(duì)話框類中添加WM_PAINT消息的響應(yīng)函數(shù)OnPaint來進(jìn)行一些繪圖工作。

            <!--[if !supportLists]-->l     <!--[endif]-->為了在鼠標(biāo)指向按鈕時(shí),讓按鈕上自己繪制的圖形不被消去,可以設(shè)置按鈕控件的“Owner Draw”屬性為“True”。

            <!--[if !supportLists]-->l     <!--[endif]-->如果希望非按鈕控件(如圖片控件和靜態(tài)文本等),也可以響應(yīng)鼠標(biāo)消息(如單擊、雙擊等),需要設(shè)置控件的“Notify”屬性為“True”。

            <!--[if !supportLists]-->l     <!--[endif]-->使用OnPaint函數(shù)在對(duì)話框客戶區(qū)的空白處(無控件的地方)繪制自己的圖形,必須屏蔽掉其中缺省的對(duì)對(duì)話框基類的OnPaint函數(shù)的調(diào)用:

            //CDialog::OnPaint();
            <!--[if !supportLists]-->l     <!--[endif]-->對(duì)話框的背景色,可以用CWnd類的成員函數(shù):

            DWORD GetSysColor( int nIndex);
            得到,其中的nIndex取為COLOR_BTNFACE。例如:
            dc.SetBkColor(GetSysColor(COLOR_BTNFACE));

            下面是部分例子代碼:(其中FillColor和ShowImg為自定義的成員函數(shù))
            void CSetDlg::OnBnClickedPenColor()
            {
                   // TODO: 在此添加控件通知處理程序代碼
                   CColorDialog colDlg(m_crLineColor);

                   if (colDlg.DoModal() == IDOK) {

                          m_crLineColor = colDlg.GetColor();

                          Invalidate();
                          UpdateWindow();
                   }
            }
            // ……
            void CSetDlg::OnPaint()
            {
                   CPaintDC dc(this); // device context for painting

                   // TODO: 在此處添加消息處理程序代碼
                   // 不為繪圖消息調(diào)用 CDialog::OnPaint()
                   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)背景模式為不透明時(shí),背景色決定線狀圖的空隙顏色(如虛線中的空隙、條紋刷的空隙和文字的空隙),可以使用CDC類的成員函數(shù)GetBkColor和SetBkColor來獲得和設(shè)置當(dāng)前的背景顏色:
            COLORREF GetBkColor( ) const; // 返回當(dāng)前的背景色
            virtual COLORREF SetBkColor( COLORREF crColor ); // 返回先前的背景色
                                                                                          // 若出錯(cuò)返回0x80000000
            2)背景模式
            背景模式影響有空隙的線狀圖的空隙(如虛線中的空隙、條紋刷的空隙和文字的空隙)用什么辦法填充。可以使用CDC類的成員函數(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的取值
            符號(hào)常量 作用 運(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)畫移動(dòng)圖形
            為了能畫移動(dòng)的位置標(biāo)識(shí)(如十字、一字)和隨鼠標(biāo)移動(dòng)畫動(dòng)態(tài)圖形(如直線、矩形、橢圓),必須在不破壞原有背景圖形的基礎(chǔ)上移動(dòng)這些圖形。
            移動(dòng)圖形采用的是異或畫圖方法,移動(dòng)圖形的過程為:異或畫圖、在原位置再異或化圖(擦除)、在新位置異或畫圖、……。

                   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;
            較完整的拖放動(dòng)態(tài)畫圖的例子,可參照下面的“3. 拖放畫動(dòng)態(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(逆時(shí)針方向,缺省值)和AD_CLOCKWISE(順時(shí)針方向)
            <!--[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.拖放畫動(dòng)態(tài)直線
            下面是一個(gè)較完整的拖放動(dòng)態(tài)畫直線的例子:
            // 類變量
            class CDrawView : public CView { 
                   //……
            protected:
                   BOOL m_bLButtonDown, m_bErase; // 判斷是否按下左鼠標(biāo)鍵

            //和是否需要擦除圖形的類變量
                   CPoint p0, pm; // 記錄直線起點(diǎn)和動(dòng)態(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::OnLButtonDown(UINT nFlags, CPoint point) {

                   m_bLButtonDown = TRUE; // 設(shè)左鼠標(biāo)鍵按下為真

                   SetCapture(); // 設(shè)置鼠標(biāo)捕獲

                   // SetCursor(LoadCursor(NULL, IDC_CROSS)); // 設(shè)置鼠標(biāo)為十字

                   p0 = point; // 保存矩形左上角

                   pm = p0; // 讓矩形右下角等于左上角
                   CView::OnLButtonDown(nFlags, point);

            }
            void CDrawView::OnMouseMove(UINT nFlags, CPoint point) {

                   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::OnMouseMove(nFlags, point);

            }
            void CDrawView::OnLButtonUp(UINT nFlags, CPoint point) {

                   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::OnLButtonUp(nFlags, point);

            }

            posted on 2011-03-01 14:03 wrh 閱讀(2445) 評(píng)論(0)  編輯 收藏 引用


            只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


            導(dǎo)航

            <2010年8月>
            25262728293031
            1234567
            891011121314
            15161718192021
            22232425262728
            2930311234

            統(tǒng)計(jì)

            常用鏈接

            留言簿(19)

            隨筆檔案

            文章檔案

            收藏夾

            搜索

            最新評(píng)論

            閱讀排行榜

            評(píng)論排行榜

            色偷偷88888欧美精品久久久| 国产成人综合久久精品尤物| 2021国内精品久久久久久影院| 久久久久久精品无码人妻| 久久久久久毛片免费播放| 久久99精品久久久久久| 久久国产一片免费观看| 久久99精品国产麻豆宅宅| 亚洲天堂久久精品| 久久久黄色大片| 97精品伊人久久久大香线蕉| 国产亚洲精久久久久久无码77777| 1000部精品久久久久久久久| 伊人久久无码精品中文字幕| 国产精品gz久久久| 久久国产乱子伦免费精品| 免费精品国产日韩热久久| 久久99久久99小草精品免视看| 久久久久久久精品妇女99| 久久精品国产国产精品四凭| 久久久久99精品成人片欧美| 奇米影视7777久久精品人人爽 | 久久精品国产亚洲av瑜伽| 99久久99久久久精品齐齐| 亚洲精品99久久久久中文字幕| 色综合久久中文色婷婷| 色偷偷88888欧美精品久久久| 日日狠狠久久偷偷色综合免费 | 日产久久强奸免费的看| 热久久这里只有精品| 狠狠狠色丁香婷婷综合久久五月| 亚洲AV无码一区东京热久久| 久久婷婷五月综合成人D啪| 无码8090精品久久一区| 久久久久久亚洲精品不卡| 国产精品99久久不卡| 亚洲国产二区三区久久| 91久久国产视频| 久久精品免费大片国产大片| 久久精品国产99久久香蕉| 激情五月综合综合久久69|