专栏导航
上一篇:第5章,[Win32 章节] :椭圆教学插图绘制程序
回到目录
下一篇:第5章,[Win32 章节] :Arc、Chord 和 Pie 教学插图
本专栏课件
关于本专栏课件的获取方法,请参考下述课节。
参考课节:MFC笔记:本专栏课件
本节前言
对于本节所讲解的知识,有可能,你会需要时不时地参考本专栏的其它文章。真的遇到了需要参考之前的文章的知识点,请你自行查阅。
我呢,也会提到一部分的参考课节。但是呢,你不应该依赖于我的主动提及。最好呢,你自己能够多去了解和查看本专栏目录。
本节,我们继续来做小的练习题。
本节的代码依然不难。
不过呢,鉴于本节的程序有点长,所以呢,我会将代码放进 Gitee 课件代码仓库里面的。
一. 插图介绍
之前的有一个课节,里面用到了如下的插图。
这个插图出现在下述课节中。
参考课节:第5章,[Win32 章节] :边框绘制函数(五)
这个插图呢,它主要的部分,是一个圆角矩形。
不过呢,它还有两个辅助部分,一个辅助部分,就是圆角矩形所在的矩形。圆角矩形,我们用实线、蓝色线条风格的画笔来绘制。
这个矩形,我们在绘制的时候,我要用虚线来绘制。那就是需要用自定义画笔,并且将这个画笔设置为 PS_DASH 风格。颜色的话,不一定要与图1 一致,你可以自己选定一个颜色。我设定的颜色是 RGB(255, 0, 255) 。
第二个辅助部分,就是四个圆角所在的椭圆了。它们呢,需要用虚线来绘制。我在自己的程序里,我是创建了一个自定义画笔,并将画笔设置为 PS_DASH、红色线条风格。
那么,在具体绘制的时候,我呢,首先是绘制矩形,然后是绘制四个辅助椭圆,最后是绘制圆角矩形。
有一个问题,如果你直接这么按次序来绘制的话,那么,在程序绘制完圆角矩形的时候,内部的四个小椭圆就会消失了。那是因为,默认地,我们会用白色画刷来填充圆角矩形的内部。就在这个填充的过程中,之前绘制的四个小椭圆,它的大部分的线条,就被白色画刷给涂抹掉了。
为了避免默认的白色画刷将四个小椭圆给涂抹掉,我们呢,需要在绘制圆角矩形之前,给设备环境选入一个 NULL_BRUSH 画刷。有了这个 NULL_BRUSH 画刷,Windows 就不会用某个画刷来填充圆角矩形的内部,而是直接沿用原来的背景颜色。
基本的绘制思路,我们就讲解完了。
接下来,我们在下一节,来展示程序代码。
二. 本节程序
代码如下。
/*------------------------------------------------------------ RoundRect 函数讲解插图 水饺编程,2026 ------------------------------------------------------------*/ #include <windows.h> LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { static TCHAR szAppName[] = TEXT("RoundRect_Teach"); 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("注册窗口类失败!"), szAppName, MB_ICONERROR); return 0; } hwnd = CreateWindow(szAppName, // window class name TEXT("RoundRect 绘图讲解图示"), // window caption WS_OVERLAPPEDWINDOW, // window style CW_USEDEFAULT, // initial x position CW_USEDEFAULT, // initial y position CW_USEDEFAULT, // initial x size CW_USEDEFAULT, // 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; } LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { HDC hdc; PAINTSTRUCT ps; RECT rect; static int xLeft, xRight, yTop, yBottom; static int xCornerEllipse, yCornerEllipse; COLORREF color; HPEN hPen, hOldPen; HBRUSH hBrush, hOldBrush; switch (message) { case WM_CREATE: xLeft = 100; xRight = 600; yTop = 100; yBottom = 500; xCornerEllipse = 160; yCornerEllipse = 120; return 0; case WM_PAINT: hdc = BeginPaint(hwnd, &ps); color = RGB(255, 0, 255); hPen = CreatePen(PS_DASH, 0, color); hOldPen = (HPEN)SelectObject(hdc, hPen); Rectangle(hdc, xLeft, yTop, xRight, yBottom); SelectObject(hdc, hOldPen); DeleteObject(hPen); color = RGB(255, 0, 0); hPen = CreatePen(PS_DASH, 0, color); hOldPen = (HPEN)SelectObject(hdc, hPen); Ellipse(hdc, xLeft, yTop, xLeft + xCornerEllipse, yTop + yCornerEllipse); Ellipse(hdc, xRight - xCornerEllipse, yTop, xRight, yTop + yCornerEllipse); Ellipse(hdc, xLeft, yBottom - yCornerEllipse, xLeft + xCornerEllipse, yBottom); Ellipse(hdc, xRight - xCornerEllipse, yBottom - yCornerEllipse, xRight, yBottom); SelectObject(hdc, hOldPen); DeleteObject(hPen); hBrush = (HBRUSH)GetStockObject(NULL_BRUSH); hOldBrush = (HBRUSH)SelectObject(hdc, hBrush); color = RGB(0, 0, 255); hPen = CreatePen(PS_SOLID, 0, color); hOldPen = (HPEN)SelectObject(hdc, hPen); RoundRect(hdc, xLeft, yTop, xRight, yBottom, xCornerEllipse, yCornerEllipse); SelectObject(hdc, hOldPen); DeleteObject(hPen); SelectObject(hdc, hOldBrush); EndPaint(hwnd, &ps); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, message, wParam, lParam); }代码本身不难,不过呢,我还是得提醒两句。
第一点,对于 static ,有它在,我们才可以在 WM_CREATE 消息中初始化一些个变量,而在 WM_PAINT 消息中使用 WM_CREATE 消息中的初始化值。
不同的消息,是处在不同的窗口过程函数 WinProc 的调用之中的。要想在不同的 WinProc 函数的调用中使用同一个变量的值,则需要将相关变量设置为 static 属性。
第二点,在本程序中,画刷我们使用了一次,并且使用的是备用画刷 NULL_BRUSH 。备用画刷也好,备用画笔也好,用完了,需要将其选出设备环境,但是不能删除它。而对于自定义画笔和自定义画刷,则需要在用完以后,选出设备环境,然后再删除它。
三. 程序编译与运行
我将解决方案和项目名称,设为 RoundRect_Teach 。源文件的名称,我将其设置为 WinMain.cpp 。
关于如何编译和运行程序,请参考下述课节。
参考课节:使用 VS2010 编写 C语言程序
参考课节:用 VS2019 编写C语言程序
程序的运行结果如下。
可以看到,图2 与图1 并不完全一致。区别主要在于画笔的颜色。
结束语
程序不难。
本节,依然是以让大家熟悉 GDI 对象的使用流程为目的。
同时呢,大家也可以有一种经验,对于某些个,你用 PhotoShop 和 Visio 软件不容易绘制的图,或许,你可以考虑用编程的方式来绘制它。
程序员可以用编程的方式来绘图,也可以学习 PhotoShop 来绘图。
编程有编程的方便。
专栏导航
上一篇:第5章,[Win32 章节] :椭圆教学插图绘制程序
回到目录
下一篇:第5章,[Win32 章节] :Arc、Chord 和 Pie 教学插图