GDI基礎(1):繪制線條和圖形


1、

繪制一個像素點:SetPixel()。

繪制直線:MoveTo(),LineTo()。

繪制多個首尾相連的線:Polyline()。

繪制矩形:FrameRect(),Rectangle(),FillRect() ,FillSolidRect()。

繪制一個四個角是弧形的矩形:RoundRect()。

繪制圓形或橢圓:Ellipse()。

繪制弧線:Arc(),ArcTo()。

繪制三角形或多邊形:Polygon()。

繪制餅形圖:Pie()。

對矩形或指定區域的像素顏色進行反轉:InvertRect()、InvertRgn()。

以上函數如果沒有參數用來指定的話則使用的是當前默認畫筆和畫刷,可以使用CDC::SelectObject()來改變當前畫筆和畫刷,而如果只是想改變畫筆或畫刷的顏色則使用SetDCPenColor()、SetDCBrushColor()即可。

Polyline(const POINT* lpPoints, int nCount)中的lpPoints是要連結的那些點的數組,nCount為點的個數。如果nCount為2的話其相當於MoveTo()和LineTo()繪制一條直線。

FrameRect()用來繪制一個矩形邊框,邊框顏色由其參數指定,矩形內部是透明的,相當於使用了透明畫刷;

Rectangle()用來繪制帶邊框的矩形,邊框顏色和類型使用當前DC默認畫筆類型,矩形內部使用當前DC默認畫刷,如果想要改變邊框或畫刷的顏色、類型,可以使用SelectObject()將指定畫筆或畫刷選入當前DC,也可以直接使用SetDCPenColor()、SetDCBrushColor()。

FillRect()用來繪制一塊無邊框的矩形,矩形內部使用指定畫刷顏色或類型。

FillSolidRect()與FillRect類似,FillSolidRect只能使用固體色(COLORREF類型),但FillRect使用畫刷,因此可以為矩形填充固體色、抖動色、陰影、位圖或使用調色板,而且FillSolidRect通常比FillRect快。

以下為使用FrameRect、Rectangle、FillRect的對比:

Arc()與ArcTo()的區別在於,Arc函數只是繪出給定的弧線,不會對畫筆位置產生影響;而ArcTo函數在工作時將會從畫筆原來所在點(默認起始為0,0)開始繪制一條直線到弧線的開始點,繪畫弧線完成后還會將畫筆移動到弧線的終點,從而對畫筆位置造成影響。下面是網上找的兩個示例圖:

 

2、

畫筆CPen、畫刷CBrush、字體CFont、位圖CBitmap、調色板CPalette等都是GDI對象,通常在函數沒有參數指定的情況下我們使用的是DC當前默認GDI對象,如在使用MoveTo/LineTo畫線的時候線條的顏色是黑色實線,即當前DC默認畫筆為黑色實線,使用Rectangle()畫矩形的時候使用的是默認的白色畫刷。我們可以使用CDC::SelectObject()來改變DC的默認GDI對象,該函數返回DC中被替換的GDI對象,我們應該保存這個舊的GDI對象,當我們不需要使用新的GDI對象的時候再使用CDC::SelectObject()將舊的GDI對象恢復到DC中。

還可以通過HGDIOBJ GetStockObject(int i)函數來獲得系統標准的GDI對象,其參數可以為:NULL_BRUSH透明(空)畫刷、SYSTEM_FONT系統字體、DEFAULT_PALETTE缺省調色板等。GetStockObject返回的類型為HGDIOBJ,所以在使用的時候還應該將其返回值強制轉換為我們所使用的GDI句柄類型,如HBRUSH、HFONT、HPALETTE等。還可以使用各GDI類型的靜態成員函數FromHandle()由這個GDI句柄獲得其對象指針。比如CBrush::FromHandle()可以由畫刷句柄獲得畫刷對象的指針,它是一個靜態成員函數。同理,對於CPen、CFont、CBitmap、CPalette等GDI對象,甚至CDC和CWnd等也包含靜態成員函數FromHandle()。實際上,MFC對各種包含內核對象的封裝類都有FromHandle(HANDLE h)方法。

CDC類的成員函數GetSafeHdc(void)可以獲得CDC對象的句柄。

下面是一個使用例子,它先將當前DC畫刷設置為了系統透明畫刷再使用Rectangle()來畫矩形:

HBRUSH hNull_Brush = (HBRUSH)GetStockObject(NULL_BRUSH);
    CBrush *pBrush = CBrush::FromHandle(hNull_Brush);
    CBrush* pOldBrush = dc.SelectObject(pBrush);
    
    CRect rect(0, 0, 100, 100);
    dc.Rectangle(&rect);

    dc.SelectObject(pOldBrush);
  pBrush->DeleteObject();

與前面的例子對比就可以看出效果:

3、

CPen是畫筆類,用來在DC上完成繪制線條的任務,常用的構造函數: 

CPen(Int style,int width ,COLORREF color);

style:畫筆樣式,可以為以下樣式:

         PS_SOLID 實線

         PS_DASH 虛線,該值只有當畫筆寬度等於1個設備單位或更小時才有效

         PS_DOT 點線,該值只有當畫筆寬度等於1個設備單位或更小時才有效

         PS_DASHDOT 點和虛線交替,該值只有當畫筆寬度等於1個設備單位或更小時才有效

         PS_DASHDOTDOT 雙點線和虛線交替,該值只有當畫筆寬度等於1個設備單位或更小時才有效

         PS_NULL 空畫筆

         PS_GEOMETRIC 幾何畫筆

         .......

width:畫筆寬度。

color:畫筆顏色。    

如果CPen在定義的時候沒有被初始化,那么在使用之前應該調用其以下的初始化函數來進行初始化。  

 CreatePen()用指定的樣式、寬度、顏色初始化畫筆。

 CreatePenIndirect()用結構LOGPEN 中指定的風格初始化畫筆。

繪制連續曲線的例子:

void CMFC_testDlg::OnMouseMove(UINT nFlags, CPoint point)
{
    // TODO: 在此添加消息處理程序代碼和/或調用默認值

    if(nFlags == MK_LBUTTON)//鼠標左鍵按下標志
    {
        CClientDC dc(this);
        CPen pen(PS_DOT, 1, RGB(255,0,0));//創建一個虛線線條,寬度為1,紅色的畫筆對象  
        CPen* pOldPen = dc.SelectObject(&pen);//將畫筆對象選入到設備描述表中  

        dc.MoveTo(m_ptOrigin);
        dc.LineTo(point);
        m_ptOrigin = point;//修改線段的起點

        dc.SelectObject(pOldPen);//恢復設備描述表 
pen.DeleteObject(); } CDialogEx::OnMouseMove(nFlags, point); }

CDC::SetROP2(int nDrawMode)用來設置畫筆繪畫的模式,其參數可以為R2_NOTXORPEN、R2_NOT等繪圖模式。R2_NOTXORPEN繪圖模式就是先把畫筆顏色與屏幕顏色異或,異或之后再取反最后得到一個顏色值顯示在屏幕上,而這種做法就會產生一個效果:比如用畫筆畫了一條線,然后再用畫筆在相同的位置畫這條線就會擦除原來畫的線。R2_NOT繪畫模式同樣有在同一個地方畫兩次相當於什么都沒畫的功能,不過R2_NOT繪畫模式第一次畫的時候顯示顏色並不是你選定的畫筆顏色,而是系統默認畫筆顏色。

所以SetROP2()可以用來當做橡皮筋來使用。

4、

CBrush為畫刷類,畫刷通常用來填充一塊區域,可以為普通固體色畫刷,位圖畫刷,陰影線畫刷等。常用的構造函數:

CBrush( COLORREF crColor ); //普通畫刷

CBrush( int nIndex, COLORREF crColor ); //陰影線畫刷

CBrush( CBitmap* pBitmap ); //位圖畫刷

crColor:畫刷或陰影線的顏色

nIndex:陰影線的風格,有以下風格可選:

            HS_HORIZONTAL 水平的陰影線
            HS_VERTICAL 垂直的陰影線
            HS_CROSS 水平和垂直方向以網格線作出陰影
            HS_BDIAGONAL 45度的向下影線(從左到右)
            HS_FDIAGONAL 45度的向上陰影線(從左到右)
            HS_DIAGCROSS 45度的網格線陰影

同CPen一樣,如果CBrush在定義的時候沒有被初始化,那么在使用之前應該調用其以下的初始化函數來進行初始化:

 CreateSolidBrush() 用指定的顏色初始化畫刷。
 CreateHatchBrush() 用指定的陰影線初始化畫刷。
 CreateBrushIndirect() 用結構LOGBRUSH中指定的風格、顏色和模式初始化畫刷。
 CreatePatternBrush() 用位圖指定的模式初始化畫刷。
 CreateDIBPatternBrush() 用獨立於設備的位圖(DIB)初始化畫刷。
 CreateSysColorBrush() 創建一個使用系統缺省顏色的畫刷。

使用陰影線畫刷:

CPaintDC dc(this);

        CRect rect(10, 10, 100, 100);
        CBrush brush(HS_HORIZONTAL, RGB(255,0,0));
        dc.FillRect(&rect, &brush);

        CRect rect2(120, 10, 210, 100);
        CBrush brush2(HS_CROSS, RGB(255,0,0));
        dc.FillRect(&rect2, &brush2);

        CRect rect3(230, 10, 320, 100);
        CBrush brush3(HS_BDIAGONAL, RGB(255,0,0));
        dc.FillRect(&rect3, &brush3);
brush.DeleteObject();

使用位圖畫刷:

//使用位圖畫刷來填充一塊矩形區域
    CClientDC dc(this);

    CBitmap bitmap;
    bitmap.LoadBitmapW(IDB_BITMAP1);//初始化位圖對象  
    CBrush brush(&bitmap);//構造位圖畫刷
  
    CRect rect(10, 10, 100, 100);
    dc.FillRect(&rect, &brush);
bimap.DeleteObject();

如果在繪圖過程中要經常改變DC中的畫刷或畫筆得顏色,可以使用SetDCBrushColor()、SetDCPenColor()函數來改變DC的畫刷或畫筆的顏色,在使用這兩個函數之前要先將系統畫刷DC_BRUSH或畫筆DC_PEN選到DC中去:

CPaintDC dc(this);
        dc.SelectObject(GetStockObject(DC_BRUSH));
        dc.SelectObject(GetStockObject(DC_PEN));
        
        //畫圓,邊框設為藍色,內部為紅色
        dc.SetDCPenColor(RGB(0,0,255));
        dc.SetDCBrushColor(RGB(255,0,0));
        dc.Pie(35,320,300,600,56,470,60,360);

        //畫餅,邊框為紅色,內部為藍色
        dc.SetDCPenColor(RGB(255,0,0));
        dc.SetDCBrushColor(RGB(0,0,255));
        dc.Ellipse(35, 100, 235, 300);

5、

CPen、CBrush、CBitmap、CFont等GID對象在使用結束后應該調用DeleteObject()函數用來釋放相關資源,而且只有這樣才能重新初始化使用。我覺得MFC中的GDI對象會在析構的時候自動調用DelectObject(),win32的話必須顯示調用DelectObject()防止內存泄露,所以用完之后再delete是一個好習慣。關於CFont和CBitmap這兩個GDI對象會在下面的文章中詳解。

6、

Windows中顯示是基於設備環境(DC)的,在使用GDI函數之前必須先獲得窗口的DC。在Win32 SDK中繪圖的話需要調用GetDC()(WM_PAINT消息響應代碼塊中為BeginPaint)獲得指定窗口的DC,繪制結束后還要調用ReleaseDC()(EndPaint())來釋放DC資源。MFC的設備環境類CDC封裝了窗口的DC對象和繪圖所需要的所有函數。CClientDC、CWindowDC、CPaintDC都是從CDC類派生而來,只要在初始化的時候傳入窗口的指針那么就可以通過這些對象的方法來方便的對窗口進行繪制等操作,而且DC資源釋放會在對象的析構函數中自動執行。還有一個CMetaFileDC類,它對圖像的保存比像素更精確,因而往往在要求較高的場合下使用,例如AutoCAD的圖形保存等。

CClientDC獲得的是窗口客戶區的DC,所以只能在客戶區畫圖,其原點坐標為客戶區左上角;

CWindowDC獲得的是整個窗口的DC,包括標題欄、邊框等,其原點坐標也是整個窗口的左上角;

CPaintDC只用在窗口重繪消息響應函數中;

GetDesktopWindow()函數可以獲得桌面窗口的指針,所以想在當前屏幕上進行繪圖操作可以類似這樣:

CWindowDC dc(GetDesktopWindow());//獲得與當前桌面窗口相關聯的CWindowDC對象

    dc.MoveTo(100, 100);  
    dc.LineTo(100, 800); 

 7、

   可以調用GradientFill()函數來繪制一塊漸變色的矩形區域或三角形區域,eg:

void CMFCApplication9Dlg::OnPaint()
{
    CPaintDC dc(this);

    TRIVERTEX vertex[2];
    vertex[0].x = 0;
    vertex[0].y = 0;
    vertex[0].Red = 0x0000;
    vertex[0].Green = 0x8000;
    vertex[0].Blue = 0x8000;
    vertex[0].Alpha = 0x0000;

    vertex[1].x = 320;
    vertex[1].y = 80;
    vertex[1].Red = 0x0000;
    vertex[1].Green = 0xd000;
    vertex[1].Blue = 0xd000;
    vertex[1].Alpha = 0x0000;
    
    GRADIENT_RECT gRect;
    gRect.UpperLeft = 0;
    gRect.LowerRight = 1;

    dc.GradientFill(vertex, 2, &gRect, 1, GRADIENT_FILL_RECT_H);
}

   

  以上繪制的是水平漸變方式的矩形,也可以修改GradientFill()的最后一個參數為GRADIENT_FILL_RECT_V來實現垂直漸變的效果,如下圖:

  

  下面為繪制一個漸變三角形的示例:

 

void CMFCApplication9Dlg::OnPaint()
{
    CPaintDC dc(this);

    TRIVERTEX vertex[3];
    vertex[0].x = 150;
    vertex[0].y = 0;
    vertex[0].Red = 0xff00;
    vertex[0].Green = 0x8000;
    vertex[0].Blue = 0x0000;
    vertex[0].Alpha = 0x0000;

    vertex[1].x = 0;
    vertex[1].y = 150;
    vertex[1].Red = 0x9000;
    vertex[1].Green = 0x0000;
    vertex[1].Blue = 0x9000;
    vertex[1].Alpha = 0x0000;

    vertex[2].x = 300;
    vertex[2].y = 150;
    vertex[2].Red = 0x9000;
    vertex[2].Green = 0x0000;
    vertex[2].Blue = 0x9000;
    vertex[2].Alpha = 0x0000;

    GRADIENT_TRIANGLE gTriangle;
    gTriangle.Vertex1 = 0;
    gTriangle.Vertex2 = 1;
    gTriangle.Vertex3 = 2;

    dc.GradientFill(vertex, 3, &gTriangle, 1, GRADIENT_FILL_TRIANGLE);
}

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM