编程中另一个非常重要的部分GDI绘图做一个讲解
2021-08-25
在上两篇文章中,我们学习了文本字符输出和编程,并且知道了如何使用常见的输出文本字符串。在本文中,我们将学习编程中GDI图形绘制的另一个非常重要的部分。 GDI 函数包含数百个 API 供我们使用。本文将讲解最常用的GDI绘图。 GDI 可以绘制点、直线和曲线,填充封闭区域、位图和文本。正文部分已经在上一篇文章中介绍过了。请参考【编程】系列第三篇:文本字符输出。
与之前的 GDI 对象一样,本文中的这些绘图函数也必须需要一个设备上下文句柄 (HDC) 作为函数参数。上一篇我们知道,HDC可以在处理过程中通过函数获取,也可以通过and获取。
既然是图画,就少不了对颜色的描述。颜色中有几种颜色的表示。其中,在GDI绘图中使用最多的,其实是一个无符号的32整数。其中,红、绿、蓝各占一个字节,最高字节不使用windows 图形编程基础,如下图:
该值可由提供的RGB宏生成,RGB的定义为:
#define RGB(r,g,b) ((COLORREF)(((BYTE)(r)|((WORD)((BYTE)(g))<<8))|(((DWORD)(BYTE)(b))<<16)))
另外还有表示颜色的结构windows 图形编程基础,一般用于位图结构信息中。
提供 sum 函数来设置和获取像素的颜色。函数原型为:
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中描述的各种类型。
提供了十几种画线功能。常用的画线有,一般用多条线段等,曲线可以画椭圆、椭圆弧、贝塞尔样条曲线。这些函数的原型请参考 MSDN。我们将通过示例来演示这些函数的用法。
如果绘图
是封闭区域,内部可以填充。当然,如果不显示填充,系统会用默认颜色填充,比如窗口背景色。我们也可以在绘制闭合图形之前创建一个画笔。如果在设备环境中选择创建的画笔,系统将用画笔填充内部区域。将关闭的常见绘图API函数包括绘制直角矩形、圆角矩形、椭圆、饼图和和弦切割。
位图输出的内容很多,包括设备相关和设备无关位图,以及位块传输、透明度、缩放等,本文仅以位图画笔为例进行演示,其他内容可写将来分开。 使用位图作为画笔时,首先使用该函数加载位图文件,然后使用创建图案画笔。
这个之前已经讨论过了,请参考【编程】系列的第三部分:文本字符输出。
绘制图形时,环境设备有5个属性会影响大部分绘图:
笔位:画线时,从笔的位置开始,笔位可以通过函数设置。
笔:绘图时,将使用当前环境中的笔进行绘图。如果未创建显示,将使用系统默认笔。
背景:某些 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); }
本例运行结果如下图所示。在图中,您可以看到线条不平滑。这是因为绘图功能没有抗锯齿功能。数字越小,混叠越明显。可以使用微软提供的GDI+绘图功能,具有抗锯齿效果。
GDI的基本绘图不难掌握。只要阅读MSDN上API的详细说明,就可以正确使用,但是创建并使用GDI对象后,一定要记得释放。
更多经验交流可以加入编程讨论QQ群:.
关注微信公众平台:程序员互动联盟(),第一时间获取原创技术文章,与(java/C/C++///)技术专家成为朋友,在线交流编程经验,收获编程基础 解决编程问题的知识。程序员互动联盟,开发者自己的家。