【Windows編程】系列第五篇:GDI圖形繪製

來源:互聯網
上載者:User

標籤:

上兩篇我們學習了文本字元輸出以及Unicode編寫程式,知道如何用常見Win32輸出文本字串,這一篇我們來學習Windows編程中另一個非常重要的部分GDI圖形繪圖。Windows的GDI函數包含數百個API可供我們使用,本篇把最常用的GDI繪圖做一個講解。GDI可以繪製點、直線曲線、填充封閉地區、位元影像以及文本,其中文本部分已經在上一篇中將了,請參考【Windows編程】系列第三篇:文本字元輸出。

跟前面的GDI對象一樣,本篇的這些繪圖函數也必須要裝置上下文控制代碼(HDC)作為函數參數,從前文我們知道,HDC可以在處理WM_PAINT的時候用BeginPaint函數擷取,也可以從GetDC、GetWindowDC拿到。

既然是畫圖,就少不了顏色的描述,Windows中的顏色有幾種表示,其中COLORREF在GDI繪製中用的最多,它實際上是一個無符號32為整型。其中紅、綠、藍各佔一個位元組,最高位元組不使用,如所示:

該值可以用Windows提供的RGB宏來產生,Windows中RGB的定義為:

#define RGB(r,g,b) ((COLORREF)(((BYTE)(r)|((WORD)((BYTE)(g))<<8))|(((DWORD)(BYTE)(b))<<16)))

除此之外,Windows還有結構體RGBQUAD也表示顏色,這種一般用於位元影像結構資訊中。

  • 畫像素點

Windows提供了SetPixel和GetPixel函數來設定和擷取像素點的顏色。函數原型為:

COLORREF SetPixel(HDC hdc, int X, int Y, COLORREF crColor);COLORREF GetPixel(HDC hdc, int nXPos, int nYPos);

 

該函數並不常使用。

  • 畫筆畫刷

在圖形繪製之前,可以建立畫筆給後續的畫圖使用,建立畫筆的API函數為:

HPEN CreatePen(int fnPenStyle, int nWidth, COLORREF crColor);HBRUSH CreateSolidBrush(COLORREF crColor);HBRUSH CreatePatternBrush(HBITMAP hbmp);HBRUSH CreateHatchBrush(int fnStyle, COLORREF clrref);

 

它可以指定畫筆風格,寬度和顏色。風格可以是實線、虛線、點虛線等,具體參考MSDN說明的各種類型。

  • 畫線條

Windows提供的畫線條函數有十幾個,常用的直線繪製為LineTo,多條線段一般用Polyline、PolylineTo、PolyPolyine等,曲線可以畫橢圓、橢圓弧、貝塞爾樣條曲線。這些函數的原型請參考MSDN,後面我們將用執行個體來示範這些函數的用法。

  • 封閉地區填充

Windows的繪圖如果是一個封閉區,則內部是可以填充的,當然如果你不顯示填充,系統會用預設顏色來填,比如視窗背景色。我們也可以在繪製封閉圖形之前建立畫刷,如果把建立的畫刷選入裝置環境中,系統將用畫刷填充內部區。常見的會封閉的繪圖API函數有畫直角矩形Rectangle、圓角矩形RoundRect、橢圓Ellipse、扇形圖Pie以及弦割圖Chord。

  • 位元影像輸出

Windows關於位元影像的輸出內容很多,包括裝置相關和裝置無關位元影像、以及位塊轉移、透明、縮放等等,本文僅針對位元影像畫刷進行執行個體示範,其他內容將來可單獨寫一篇介紹。用位元影像做畫刷時先要使用LoadImage函數載入位元影像檔案,然後用CreatePatternBrush建立一個模式畫刷即可。

  • 文本輸出

這個在前面已經討論過了,請參考【Windows編程】系列第三篇:文本字元輸出一文。

  • 繪圖屬性

在繪製圖形時,環境裝置有5個屬性會影響大多數繪圖:

畫筆位置:在畫線條時,會從畫筆所在的位置開始畫,畫筆位置可以用MoveToEx函數來設定。

畫筆:繪圖時會採用當前環境中的畫筆進行繪製,如果顯示不建立,將會用系統預設的畫筆。

背景:某些GDI會有透明和不透明的設定。

背景顏色:比如文本輸出的間隙顏色。

繪製模式:比如劃線是可以設定實線、虛線等,填充時可能有不同的填充繪製模式。

下面我們通過一個完整的執行個體,來示範上面這些常見函數的具體運用以及實際使用效果。

#include <windows.h>static TCHAR szAppName[] = TEXT("GDI Test");static LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow){     HWND     hWnd;     MSG      msg;     WNDCLASS wndclass;     wndclass.style         = CS_HREDRAW | CS_VREDRAW;     wndclass.lpfnWndProc   = WndProc;     wndclass.cbClsExtra    = 0;     wndclass.cbWndExtra    = 0;     wndclass.hInstance     = hInstance;     wndclass.hIcon         = LoadIcon(NULL, IDI_APPLICATION);     wndclass.hCursor       = LoadCursor(NULL, IDC_ARROW);     wndclass.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);     wndclass.lpszMenuName  = NULL;     wndclass.lpszClassName = szAppName;     if (!RegisterClass(&wndclass))     {          MessageBox (NULL, TEXT("This program requires Windows NT!"), szAppName, MB_ICONERROR);          return 0;     }          hWnd = CreateWindow(szAppName,            // window class name                          szAppName,           // window caption                          WS_OVERLAPPEDWINDOW, // window style                          CW_USEDEFAULT,       // initial x position                          CW_USEDEFAULT,       // initial y position                          400,                 // initial x size                          300,                 // initial y size                          NULL,                // parent window handle                          NULL,                // window menu handle                          hInstance,           // program instance handle                          NULL);               // creation parameters          ShowWindow(hWnd, iCmdShow);     UpdateWindow(hWnd);          while (GetMessage(&msg, NULL, 0, 0))     {          TranslateMessage(&msg);          DispatchMessage(&msg);     }     return msg.wParam;}//繪製指定屬性的直線static void DrawLine(HDC hDC, int x0, int y0, int x1, int y1, int style, int width, COLORREF color){HPEN hPen = CreatePen(style, width, color);HPEN hOldPen = (HPEN)SelectObject(hDC, hPen);MoveToEx(hDC, x0, y0, NULL);LineTo(hDC, x1, y1);SelectObject(hDC, hOldPen);DeleteObject(hPen);}//繪製實心圓static void DrawCircle(HDC hDC, int x, int y, int len, COLORREF color){HBRUSH hBrush = CreateSolidBrush(color);HBRUSH hOldBrush = (HBRUSH)SelectObject(hDC, hBrush);HPEN hPen = CreatePen(PS_SOLID, 1, color);HPEN hOldPen = (HPEN)SelectObject(hDC, hPen);Ellipse(hDC, x-len/2, y-len/2, x+len/2, y+len/2);SelectObject(hDC, hOldBrush);DeleteObject(hPen);SelectObject(hDC, hOldPen);DeleteObject(hOldBrush);}//繪製填充矩形static void DrawRect(HDC hDC, int left, int top, int width, int height, int style, COLORREF color){HBRUSH hBrush = CreateHatchBrush(style, color);HBRUSH hOldBrush = (HBRUSH)SelectObject(hDC, hBrush);Rectangle(hDC, left, top, left+width, top+height);SelectObject(hDC, hOldBrush);DeleteObject(hOldBrush);}//繪製位元影像填充矩形static void DrawBmpRect(HDC hDC, int left, int top, int width, int height, LPCTSTR file){HBITMAP hBitmap = (HBITMAP)LoadImage(NULL, file, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE|LR_CREATEDIBSECTION);HBRUSH hBrush = CreatePatternBrush(hBitmap);HBRUSH hOldBrush = (HBRUSH)SelectObject(hDC, hBrush);Rectangle(hDC, left, top, left+width, top+height);SelectObject(hDC, hOldBrush);DeleteObject(hOldBrush);DeleteObject(hBitmap);}static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){HDC         hDC;PAINTSTRUCT ps;switch (message){case WM_CREATE:return 0;case WM_PAINT:{hDC = BeginPaint(hWnd, &ps);for (int i=10; i<50; i+=4){SetPixel(hDC, i, 10, RGB(0, 0, 0)); //繪製像素點}                        //繪製不同模式的直線DrawLine(hDC, 120, 30, 200, 30, PS_SOLID, 2, RGB(0,0,0));DrawLine(hDC, 120, 50, 200, 50, PS_DASH, 1, RGB(100,0,200));DrawLine(hDC, 120, 70, 200, 70, PS_DASHDOT, 1, RGB(100,250,100));                        //繪製弧線、弦割線、餅圖Arc(hDC, 10, 30, 40, 50, 40, 30, 10, 40);Chord(hDC, 10, 60, 40, 80, 40, 60, 10, 70);Pie(hDC, 10, 90, 40, 110, 40, 90, 10, 100);POINT pt[4] = {{90,130},{60,40},{140,150},{160,80}};                        //繪製橢圓、矩形Ellipse(hDC,pt[0].x, pt[0].y, pt[1].x, pt[1].y);Rectangle(hDC, pt[2].x, pt[2].y, pt[3].x, pt[3].y);                        //繪製貝茲路徑PolyBezier(hDC, pt, 4);                        //標出貝茲路徑的四個錨點DrawCircle(hDC, pt[0].x, pt[0].y, 8, RGB(0,255,0));DrawCircle(hDC, pt[1].x, pt[1].y, 8, RGB(0,0,255));DrawCircle(hDC, pt[2].x, pt[2].y, 8, RGB(0,0,0));DrawCircle(hDC, pt[3].x, pt[3].y, 8, RGB(255,0,0));                        //繪製圓DrawCircle(hDC, 100, 180, 60, RGB(0, 250, 250));                        //繪製不同填充模式的矩形DrawRect(hDC, 220, 20, 60, 40, HS_BDIAGONAL, RGB(255,0,0));DrawRect(hDC, 220, 80, 60, 40, HS_CROSS, RGB(0,255,0));DrawRect(hDC, 290, 20, 60, 40, HS_DIAGCROSS, RGB(0,0,255));DrawRect(hDC, 290, 80, 60, 40, HS_VERTICAL, RGB(0,0,0));                        //繪製位元影像DrawBmpRect(hDC, 180, 140, 180, 100, TEXT("chenggong.bmp"));                        //繪製文本TextOut(hDC, 20, 220, TEXT("GDI畫圖輸出測試程式"), 11);}EndPaint(hWnd, &ps);return 0;case WM_DESTROY:PostQuitMessage(0);return 0 ;}return DefWindowProc (hWnd, message, wParam, lParam);}

 

本執行個體運行結果如所示,圖中可以看到線條不平滑,這是因為Win32的畫圖函數是沒有消除鋸齒功能的,圖越小,鋸齒越明顯。可以使用微軟提供的GDI+繪圖函數,具有消除鋸齒效果。

Windows的GDI基本繪製其實並不難掌握,只要仔細閱讀MSDN上API的詳細使用說明就一定能正確使用,但是在建立GDI對象並使用後,一定要記得釋放。

 

關注公眾平台:程式員互動聯盟(coder_online),你可以第一時間擷取原創技術文章,和(java/C/C++/Android/Windows/Linux)技術大牛做朋友,線上交流編程經驗,擷取編程基礎知識,解決編程問題。程式員互動聯盟,開發人員自己的家。

 

轉載請註明出處,謝謝合作!

 

【Windows編程】系列第五篇:GDI圖形繪製

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.