Windows编程系列:图形编程基础2
通过函数BeginPaint画图
1、创建一个Windows桌面应用程序
2、找到WM_PAINT消息的处理函数,添加代码如下:
1 case WM_PAINT: 2 { 3 PAINTSTRUCT ps; 4 HDC hdc = BeginPaint(hWnd, &ps); 5 TextOut(hdc, 10, 20, L"HelloWorld", 10); //绘制文本 6 Ellipse(hdc, 50, 50, 200, 200); //绘制椭圆 7 EndPaint(hWnd, &ps); 8 } 9 break;
这里主要用到了TextOut和Ellipse函数来进行文本绘制和椭圆绘制。
TextOut函数声明如下:
1 BOOL TextOutW( 2 [in] HDC hdc, 3 [in] int x, 4 [in] int y, 5 [in] LPCWSTR lpString, 6 [in] int c 7 );
参数说明:
[in] hdc
设备上下文的句柄。
[in] x
系统用于对齐字符串的引用点的 x 坐标(以逻辑坐标表示)。
[in] y
系统用于对齐字符串的引用点的 y 坐标(以逻辑坐标表示)。
[in] lpString
指向要绘制的字符串的指针。 字符串不需要以零结尾,因为 cchString 指定字符串的长度。
[in] c
lpString 指向字符串的长度(以字符为单位)。
返回值:
成功,返回非0,失败,返回0
Ellipse函数声明如下:
1 BOOL Ellipse( 2 [in] HDC hdc, 3 [in] int left, 4 [in] int top, 5 [in] int right, 6 [in] int bottom 7 );
参数说明:
[in] hdc
设备上下文的句柄。
[in] left
边界矩形左上角的 x 坐标(以逻辑坐标表示)。
[in] top
边界矩形左上角的 y 坐标(以逻辑坐标表示)。
[in] right
边界矩形右下角的 x 坐标(以逻辑坐标表示)。
[in] bottom
边界矩形右下角的 y 坐标(以逻辑坐标表示)。
返回值:
成功,返回非0,失败,返回0
3、运行效果
验证BeginPaint只用于无效区域的绘图
1、创建一个Windows桌面应用程序
2、在WM_LBUTTON消息处理函数中,产生一个从(100,100)到(200,200)的无效区域范围,添加代码如下:
case WM_LBUTTONDOWN: { RECT rect{ 100,100,200,200 }; InvalidateRect(hWnd, &rect, FALSE); bDown = TRUE; } break;
3、在WM_PAINT的消息处理函数中,从(0,0)到(400,400)进行画线,
1 case WM_PAINT: 2 { 3 PAINTSTRUCT ps; 4 HDC hdc = BeginPaint(hWnd, &ps); 5 if (bDown) 6 { 7 MoveToEx(hdc, 0, 0, NULL); //移动到(0,0)位置 8 LineTo(hdc, 400, 400); //绘制从(0,0)到(400,400)的线 9 } 10 EndPaint(hWnd, &ps); 11 } 12 break;
4、由于无效区域只在(100,100)到(200,200),所以当鼠标按下时只有这个区域会进行绘制,运行效果如下
5、如果此时改变窗口大小,会使整个客户区无效,就能绘制出完整的线,效果如下
以定时间隔进行绘制
可以通过使用 SetTimer 函数创建计时器,按定时间隔绘制。 通过使用计时器定期向窗口过程发送 WM_TIMER 消息,应用程序可以在其他应用程序继续运行时在工作区中执行简单的动画。
1、创建一个Windows桌面应用工程
2、定义一些全局变量
1 RECT rcCurrent = { 0,0,20,20 }; 2 POINT aptStar[6] = { 10,1,1,19,19,6,1,6,19,19,10,1 }; 3 int X = 2, Y = -1, idTimer = -1; 4 BOOL fVisible = FALSE; 5 HDC hdc;
3、消息处理函数如下
在WM_CREATE中计算起始点、初始化DC和创建定时器
在WM_SIZE中处理窗口大小变化时的逻辑
在WM_TIMER中处理定时器逻辑
在WM_PAINT中处理绘制绘制逻辑
8 LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 9 { 10 PAINTSTRUCT ps; 11 RECT rc; 12 13 switch (message) 14 { 15 case WM_CREATE: 16 //计算起始点 17 GetClientRect(hWnd, &rc); 18 OffsetRect(&rcCurrent, rc.right / 2, rc.bottom / 2); 19 20 //初始化DC 21 hdc = GetDC(hWnd); 22 SetViewportOrgEx(hdc, rcCurrent.left, rcCurrent.top, NULL); //哪个设备点映射到窗口原点 (0,0) 23 24 SetROP2(hdc, R2_NOT); 25 26 //开启定时器 27 SetTimer(hWnd, idTimer = 1, 10, NULL); 28 return 0L; 29 case WM_COMMAND: 30 { 31 int wmId = LOWORD(wParam); 32 // 分析菜单选择: 33 switch (wmId) 34 { 35 case IDM_ABOUT: 36 DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About); 37 break; 38 case IDM_EXIT: 39 DestroyWindow(hWnd); 40 break; 41 default: 42 return DefWindowProc(hWnd, message, wParam, lParam); 43 } 44 } 45 break; 46 case WM_PAINT: 47 { 48 BeginPaint(hWnd, &ps); 49 if (!fVisible) 50 fVisible = Polyline(hdc, aptStar, 6); 51 EndPaint(hWnd, &ps); 52 } 53 break; 54 case WM_DESTROY: 55 if (hdc) 56 ReleaseDC(hWnd, hdc); 57 KillTimer(hWnd, 1); 58 PostQuitMessage(0); 59 return 0L; 60 case WM_SIZE: 61 switch (wParam) 62 { 63 case SIZE_MINIMIZED: 64 //最小化的时候停止定时器 65 KillTimer(hWnd, 1); 66 idTimer = -1; 67 break; 68 case SIZE_RESTORED: 69 //如果绘制的星不在客户区,就重新移动到客户区 70 if (rcCurrent.right > (int)LOWORD(lParam)) 71 { 72 rcCurrent.left = (rcCurrent.right = (int)LOWORD(lParam)) - 20; 73 } 74 75 if (rcCurrent.bottom > (int)HIWORD(lParam)) 76 { 77 rcCurrent.top = (rcCurrent.bottom = (int)HIWORD(lParam)) - 20; 78 } 79 break; 80 case SIZE_MAXIMIZED: 81 if (idTimer == -1) 82 SetTimer(hWnd, idTimer, 10, NULL); 83 break; 84 default: 85 break; 86 } 87 return 0L; 88 case WM_TIMER: 89 //如果绘制的星是可见的,就隐藏它 90 if (fVisible) 91 Polyline(hdc, aptStar, 6); 92 93 GetClientRect(hWnd, &rc); 94 95 if (rcCurrent.left + X < rc.left || 96 rcCurrent.right + X > rc.right) 97 X = -X; 98 if (rcCurrent.top + Y < rc.top || 99 rcCurrent.bottom + Y > rc.bottom) 100 Y = -Y; 101 102 //在新的位置显示绘制的星 103 OffsetRect(&rcCurrent, X, Y); 104 SetViewportOrgEx(hdc, rcCurrent.left, rcCurrent.top, NULL); 105 fVisible = Polyline(hdc, aptStar, 6); 106 return 0L; 107 case WM_ERASEBKGND: 108 fVisible = FALSE; 109 return DefWindowProc(hWnd, message, wParam, lParam); 110 } 111 return DefWindowProc(hWnd, message, wParam, lParam); 112 }
4、运行效果如下
更改文本颜色
1、创建一个Windows桌面应用程序
2、在WM_PAINT消息的处理函数中添加如下代码
1 case WM_PAINT: 2 { 3 PAINTSTRUCT ps; 4 HDC hdc = BeginPaint(hWnd, &ps); 5 SetTextColor(hdc, RGB(0, 128, 128)); 6 TextOut(hdc, 300, 300, L"HelloWorld", 10); 7 EndPaint(hWnd, &ps); 8 } 9 break;
3、运行效果
参考资料:
https://learn.microsoft.com/zh-cn/windows/win32/gdi/drawing-at-timed-intervals
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
2020-04-08 C#中的PLINQ(并行LINQ)