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

windows1

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

跟前面的GDI對象同樣,本篇的這些繪圖函數也必需要設備上下文句柄(HDC)做爲函數參數,從前文咱們知道,HDC能夠在處理WM_PAINT的時候用BeginPaint函數獲取,也能夠從GetDC、GetWindowDC拿到。程序員

既然是畫圖,就少不了顏色的描述,Windows中的顏色有幾種表示,其中COLORREF在GDI繪製中用的最多,它其實是一個無符號32爲整型。其中紅、綠、藍各佔一個字節,最高字節不使用,以下圖所示:編程

colorref

該值能夠用Windows提供的RGB宏來生成,Windows中RGB的定義爲:windows

#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函數爲:ui

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+繪圖函數,具備抗鋸齒效果。

gdi_output

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

 更多經驗交流能夠加入Windows編程討論QQ羣454398517


關注微信公衆平臺:程序員互動聯盟(coder_online),你能夠第一時間獲取原創技術文章,和(java/C/C++/Android/Windows/Linux)技術大牛作朋友,在線交流編程經驗,獲取編程基礎知識,解決編程問題。程序員互動聯盟,開發人員本身的家。

 image010

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

相關文章
相關標籤/搜索