1、创建一个Windows桌面应用程序

2、找到WM_PAINT消息的处理函数,添加代码如下:
case WM_PAINT:{PAINTSTRUCT ps;HDC hdc = BeginPaint(hWnd, &ps);TextOut(hdc, 10, 20, L"HelloWorld", 10); //绘制文本Ellipse(hdc, 50, 50, 200, 200); //绘制椭圆EndPaint(hWnd, &ps);}break;
这里主要用到了TextOut和Ellipse函数来进行文本绘制和椭圆绘制。
TextOut函数声明如下:
BOOL TextOutW([in] HDC hdc,[in] int x,[in] int y,[in] LPCWSTR lpString,[in] int c);
参数说明:
[in] hdc
设备上下文的句柄。
[in] x
系统用于对齐字符串的引用点的 x 坐标(以逻辑坐标表示)。
[in] y
系统用于对齐字符串的引用点的 y 坐标(以逻辑坐标表示)。
[in] lpString
指向要绘制的字符串的指针。 字符串不需要以零结尾,因为 cchString 指定字符串的长度。
[in] c
lpString 指向字符串的长度(以字符为单位)。
返回值:
成功,返回非0,失败,返回0
Ellipse函数声明如下:
BOOL Ellipse([in] HDC hdc,[in] int left,[in] int top,[in] int right,[in] int bottom);
参数说明:
[in] hdc
设备上下文的句柄。
[in] left
边界矩形左上角的 x 坐标(以逻辑坐标表示)。
[in] top
边界矩形左上角的 y 坐标(以逻辑坐标表示)。
[in] right
边界矩形右下角的 x 坐标(以逻辑坐标表示)。
[in] bottom
边界矩形右下角的 y 坐标(以逻辑坐标表示)。
返回值:
成功,返回非0,失败,返回0
3、运行效果

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)进行画线,
case WM_PAINT:{PAINTSTRUCT ps;HDC hdc = BeginPaint(hWnd, &ps);if (bDown){MoveToEx(hdc, 0, 0, NULL); //移动到(0,0)位置LineTo(hdc, 400, 400); //绘制从(0,0)到(400,400)的线}EndPaint(hWnd, &ps);}break;
4、由于无效区域只在(100,100)到(200,200),所以当鼠标按下时只有这个区域会进行绘制,运行效果如下

5、如果此时改变窗口大小,会使整个客户区无效,就能绘制出完整的线,效果如下

可以通过使用 SetTimer 函数创建计时器,按定时间隔绘制。 通过使用计时器定期向窗口过程发送 WM_TIMER 消息,应用程序可以在其他应用程序继续运行时在工作区中执行简单的动画。
1、创建一个Windows桌面应用工程
2、定义一些全局变量
RECT rcCurrent = { 0,0,20,20 };POINT aptStar[6] = { 10,1,1,19,19,6,1,6,19,19,10,1 };int X = 2, Y = -1, idTimer = -1;BOOL fVisible = FALSE;HDC hdc;
3、消息处理函数如下
在WM_CREATE中计算起始点、初始化DC和创建定时器
在WM_SIZE中处理窗口大小变化时的逻辑
在WM_TIMER中处理定时器逻辑
在WM_PAINT中处理绘制绘制逻辑
RESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){PAINTSTRUCT ps;RECT rc;switch (message){case WM_CREATE://计算起始点GetClientRect(hWnd, &rc);OffsetRect(&rcCurrent, rc.right / 2, rc.bottom / 2);//初始化DChdc = GetDC(hWnd);SetViewportOrgEx(hdc, rcCurrent.left, rcCurrent.top, NULL); //哪个设备点映射到窗口原点 (0,0)SetROP2(hdc, R2_NOT);//开启定时器SetTimer(hWnd, idTimer = 1, 10, NULL);return 0L;case WM_COMMAND:{int wmId = LOWORD(wParam);// 分析菜单选择:switch (wmId){case IDM_ABOUT:DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);break;case IDM_EXIT:DestroyWindow(hWnd);break;default:return DefWindowProc(hWnd, message, wParam, lParam);}}break;case WM_PAINT:{BeginPaint(hWnd, &ps);if (!fVisible)fVisible = Polyline(hdc, aptStar, 6);EndPaint(hWnd, &ps);}break;case WM_DESTROY:if (hdc)ReleaseDC(hWnd, hdc);KillTimer(hWnd, 1);PostQuitMessage(0);return 0L;case WM_SIZE:switch (wParam){case SIZE_MINIMIZED://最小化的时候停止定时器KillTimer(hWnd, 1);idTimer = -1;break;case SIZE_RESTORED://如果绘制的星不在客户区,就重新移动到客户区if (rcCurrent.right > (int)LOWORD(lParam)){rcCurrent.left = (rcCurrent.right = (int)LOWORD(lParam)) - 20;}if (rcCurrent.bottom > (int)HIWORD(lParam)){rcCurrent.top = (rcCurrent.bottom = (int)HIWORD(lParam)) - 20;}break;case SIZE_MAXIMIZED:if (idTimer == -1)SetTimer(hWnd, idTimer, 10, NULL);break;default:break;}return 0L;case WM_TIMER://如果绘制的星是可见的,就隐藏它if (fVisible)Polyline(hdc, aptStar, 6);GetClientRect(hWnd, &rc);if (rcCurrent.left + X < rc.left ||rcCurrent.right + X > rc.right)X = -X;if (rcCurrent.top + Y < rc.top ||rcCurrent.bottom + Y > rc.bottom)Y = -Y;//在新的位置显示绘制的星OffsetRect(&rcCurrent, X, Y);SetViewportOrgEx(hdc, rcCurrent.left, rcCurrent.top, NULL);fVisible = Polyline(hdc, aptStar, 6);return 0L;case WM_ERASEBKGND:fVisible = FALSE;return DefWindowProc(hWnd, message, wParam, lParam);}return DefWindowProc(hWnd, message, wParam, lParam);}
4、运行效果如下

1、创建一个Windows桌面应用程序
2、在WM_PAINT消息的处理函数中添加如下代码
case WM_PAINT:{PAINTSTRUCT ps;HDC hdc = BeginPaint(hWnd, &ps);SetTextColor(hdc, RGB(0, 128, 128));TextOut(hdc, 300, 300, L"HelloWorld", 10);EndPaint(hWnd, &ps);}break;
3、运行效果

示例代码
https://github.com/zhaotianff/WindowsProgramming/tree/master/Drawing
https://learn.microsoft.com/zh-cn/windows/win32/gdi/drawing-at-timed-intervals