Windows API窗口绘图程序设计
Windows API窗口绘图程序设计实验博客
实验简介
本次实验使用Windows原生API编写窗口程序,实现鼠标交互绘图功能:在窗口内点击鼠标左键,在点击位置绘制边长10‑100随机大小、红色填充的正方形。熟悉Windows窗口消息机制、设备上下文GDI绘图、鼠标消息响应、随机数生成等知识点。开发环境为Visual Studio,采用Win32项目。
功能需求
- 创建标准Windows应用窗口。
- 鼠标左键按下,获取点击的客户区坐标。
- 生成10~100之间随机的正方形边长。
- 使用红色画刷填充绘制正方形。
- 处理窗口重绘、窗口关闭消息。
完整源代码
#include <windows.h>
#include <stdlib.h>
#include <time.h>
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT("RandomRedSquare");
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("程序需要在Windows NT及以上版本运行!"), szAppName, MB_ICONERROR);
return 0;
}
hwnd = CreateWindow(szAppName,
TEXT("Random Red Square"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL);
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变量消息之间保留数值
static int xClick, yClick;
static int sideLength = 0;
switch (message)
{
case WM_CREATE:
// 设置随机数种子,程序启动只执行一次
srand((unsigned)time(NULL));
return 0;
case WM_LBUTTONDOWN:
// 获取鼠标左键点击客户区坐标
xClick = LOWORD(lParam);
yClick = HIWORD(lParam);
// 生成10‑100随机边长:rand()%91得到0‑90,加10得到10‑100
sideLength = 10 + rand() % 91;
// 触发窗口重绘,执行WM_PAINT绘图
InvalidateRect(hwnd, NULL, TRUE);
return 0;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
if (sideLength > 0)
{
// 创建红色实心画刷
HBRUSH hRedBrush = CreateSolidBrush(RGB(255, 0, 0));
HBRUSH hOldBrush = (HBRUSH)SelectObject(hdc, hRedBrush);
// Rectangle:左上(xClick,yClick),右下(xClick+边长,yClick+边长)
Rectangle(hdc, xClick, yClick, xClick + sideLength, yClick + sideLength);
// GDI资源归还与释放,防止内存泄漏
SelectObject(hdc, hOldBrush);
DeleteObject(hRedBrush);
}
EndPaint(hwnd, &ps);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
核心代码解析
1. WinMain入口函数
WinMain是Windows程序入口,完成窗口类注册、创建窗口、显示窗口、消息循环。Windows程序依靠消息循环,操作系统把鼠标、窗口事件封装成消息交给WndProc窗口过程函数处理。
2. WM_CREATE 窗口创建消息
窗口刚创建时执行,调用srand((unsigned)time(NULL))设置随机数种子,保证每次运行随机得到不同正方形大小。
3. WM_LBUTTONDOWN 鼠标左键按下消息
LOWORD(lParam)、HIWORD(lParam):从消息参数提取鼠标点击的X、Y坐标(窗口客户区)。sideLength = 10 + rand() %91,生成范围10‑100的边长。InvalidateRect()使窗口无效,系统产生WM_PAINT消息,触发绘图。
Windows不允许直接在鼠标消息里面绘图,绘图逻辑统一放在
WM_PAINT,窗口被遮挡、最小化恢复时会自动重绘。
4. WM_PAINT绘图消息
BeginPaint / EndPaint是一对API,专门用于WM_PAINT内部获取绘图设备上下文HDC。CreateSolidBrush(RGB(255,0,0))创建红色画刷;SelectObject把画刷选入设备上下文。Rectangle(hdc,左,上,右,下)绘制矩形,长宽相等就是正方形。- 重点:绘图结束必须
SelectObject换回旧画刷,DeleteObject释放GDI对象,避免资源泄露。
5. WM_DESTROY关闭窗口
点击窗口关闭按钮,发送退出消息,结束消息循环,程序退出。
运行操作步骤
- VS新建空项目Win32项目,添加
.cpp源文件,粘贴完整代码。 - 编译运行,弹出白色窗口。
- 在窗口任意位置点击鼠标左键,窗口就会在点击位置画出红色填充正方形,每次点击正方形大小随机(10‑100像素)。
- 关闭窗口结束程序,截取运行效果图保存。
遇到的问题与踩坑
1、窗口无法创建
初次编译时,未正确链接 user32.lib、gdi32.lib 等库,出现链接错误。手动添加后已修复
2、正方形绘制位置偏移
最初误将屏幕坐标当作客户区坐标使用。后来查阅资料后确认WM_LBUTTONDOWN 的 lParam 中 LOWORD 和 HIWORD 已经是相对于客户区的坐标,直接使用即可。
小组作业小结
通过本次实验,完成基于Win32 API的随机红色正方形窗口程序,加深了对Windows窗口程序设计的理解。
- 掌握Win32程序基础框架:
WinMain完成窗口类注册、窗口创建与消息循环;WndProc窗口过程函数处理各类消息,理解Windows消息驱动的编程核心模型。 - 掌握GDI基础绘图流程:利用
BeginPaint/EndPaint获取绘图设备环境,通过CreateSolidBrush创建画刷、SelectObject选入设备上下文,调用Rectangle绘制填充图形,使用完毕恢复、释放GDI绘图对象。 - 掌握鼠标消息处理:
WM_LBUTTONDOWN鼠标左键消息的lParam保存鼠标坐标,通过LOWORD、HIWORD提取点击位置,结合随机数,实现每次点击生成大小不等正方形的功能。 - 懂得Windows绘图需要依靠
WM_PAINT重绘消息,理解GDI资源要手动释放,防止产生资源泄漏。

浙公网安备 33010602011771号