編程中另一個非常重要的部分GDI繪圖做一個講解
2021-08-25
在上兩篇文章中,我們學習了文本字符輸出和編程,并且知道了如何使用常見的輸出文本字符串。在本文中,我們將學習編程中GDI圖形繪制的另一個非常重要的部分。 GDI 函數(shù)包含數(shù)百個 API 供我們使用。本文將講解最常用的GDI繪圖。 GDI 可以繪制點、直線和曲線,填充封閉區(qū)域、位圖和文本。正文部分已經在上一篇文章中介紹過了。請參考【編程】系列第三篇:文本字符輸出。
與之前的 GDI 對象一樣,本文中的這些繪圖函數(shù)也必須需要一個設備上下文句柄 (HDC) 作為函數(shù)參數(shù)。上一篇我們知道,HDC可以在處理過程中通過函數(shù)獲取,也可以通過and獲取。
既然是圖畫,就少不了對顏色的描述。顏色中有幾種顏色的表示。其中,在GDI繪圖中使用最多的,其實是一個無符號的32整數(shù)。其中,紅、綠、藍各占一個字節(jié),最高字節(jié)不使用windows 圖形編程基礎,如下圖:
該值可由提供的RGB宏生成,RGB的定義為:
#define RGB(r,g,b) ((COLORREF)(((BYTE)(r)|((WORD)((BYTE)(g))<<8))|(((DWORD)(BYTE)(b))<<16)))
另外還有表示顏色的結構windows 圖形編程基礎,一般用于位圖結構信息中。
提供 sum 函數(shù)來設置和獲取像素的顏色。函數(shù)原型為:
COLORREF SetPixel(HDC hdc, int X, int Y, COLORREF crColor); COLORREF GetPixel(HDC hdc, int nXPos, int nYPos);
這個功能不常用。
在繪制圖形之前,您可以為后續(xù)繪制創(chuàng)建一個畫筆。創(chuàng)建畫筆的API函數(shù)為:
HPEN CreatePen(int fnPenStyle, int nWidth, COLORREF crColor); HBRUSH CreateSolidBrush(COLORREF crColor); HBRUSH CreatePatternBrush(HBITMAP hbmp); HBRUSH CreateHatchBrush(int fnStyle, COLORREF clrref);
它可以指定畫筆樣式、寬度和顏色。樣式可以是實線、虛線、虛線等,具體請參考MSDN中描述的各種類型。
提供了十幾種畫線功能。常用的畫線有,一般用多條線段等,曲線可以畫橢圓、橢圓弧、貝塞爾樣條曲線。這些函數(shù)的原型請參考 MSDN。我們將通過示例來演示這些函數(shù)的用法。
如果繪圖
是封閉區(qū)域,內部可以填充。當然,如果不顯示填充,系統(tǒng)會用默認顏色填充,比如窗口背景色。我們也可以在繪制閉合圖形之前創(chuàng)建一個畫筆。如果在設備環(huán)境中選擇創(chuàng)建的畫筆,系統(tǒng)將用畫筆填充內部區(qū)域。將關閉的常見繪圖API函數(shù)包括繪制直角矩形、圓角矩形、橢圓、餅圖和和弦切割。
位圖輸出的內容很多,包括設備相關和設備無關位圖,以及位塊傳輸、透明度、縮放等,本文僅以位圖畫筆為例進行演示,其他內容可寫將來分開。 使用位圖作為畫筆時,首先使用該函數(shù)加載位圖文件,然后使用創(chuàng)建圖案畫筆。
這個之前已經討論過了,請參考【編程】系列的第三部分:文本字符輸出。
繪制圖形時,環(huán)境設備有5個屬性會影響大部分繪圖:
筆位:畫線時,從筆的位置開始,筆位可以通過函數(shù)設置。
筆:繪圖時,將使用當前環(huán)境中的筆進行繪圖。如果未創(chuàng)建顯示,將使用系統(tǒng)默認筆。
背景:某些 GDI 將具有透明和不透明設置。
背景顏色:例如文本輸出的間隙顏色。
繪制模式:比如可以設置實線、虛線等進行繪制,填充時可能會有不同的填充繪制模式。
下面我們用一個完整的例子來演示上述常用功能的具體應用和實際使用效果。
#includestatic 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); }
本例運行結果如下圖所示。在圖中,您可以看到線條不平滑。這是因為繪圖功能沒有抗鋸齒功能。數(shù)字越小,混疊越明顯??梢允褂梦④浱峁┑腉DI+繪圖功能,具有抗鋸齒效果。
GDI的基本繪圖不難掌握。只要閱讀MSDN上API的詳細說明,就可以正確使用,但是創(chuàng)建并使用GDI對象后,一定要記得釋放。
更多經驗交流可以加入編程討論QQ群:.
關注微信公眾平臺:程序員互動聯(lián)盟(),第一時間獲取原創(chuàng)技術文章,與(java/C/C++///)技術專家成為朋友,在線交流編程經驗,收獲編程基礎 解決編程問題的知識。程序員互動聯(lián)盟,開發(fā)者自己的家。