Windows API窗口绘图程序设计

Windows API窗口绘图程序设计实验博客

实验简介

本次实验使用Windows原生API编写窗口程序,实现鼠标交互绘图功能:在窗口内点击鼠标左键,在点击位置绘制边长10‑100随机大小、红色填充的正方形。熟悉Windows窗口消息机制、设备上下文GDI绘图、鼠标消息响应、随机数生成等知识点。开发环境为Visual Studio,采用Win32项目。

功能需求

  1. 创建标准Windows应用窗口。
  2. 鼠标左键按下,获取点击的客户区坐标。
  3. 生成10~100之间随机的正方形边长。
  4. 使用红色画刷填充绘制正方形。
  5. 处理窗口重绘、窗口关闭消息。

完整源代码

#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关闭窗口

点击窗口关闭按钮,发送退出消息,结束消息循环,程序退出。

运行操作步骤

  1. VS新建空项目Win32项目,添加.cpp源文件,粘贴完整代码。
  2. 编译运行,弹出白色窗口。
  3. 在窗口任意位置点击鼠标左键,窗口就会在点击位置画出红色填充正方形,每次点击正方形大小随机(10‑100像素)。
  4. 关闭窗口结束程序,截取运行效果图保存。

遇到的问题与踩坑

1、窗口无法创建
初次编译时,未正确链接 user32.lib、gdi32.lib 等库,出现链接错误。手动添加后已修复
2、正方形绘制位置偏移
最初误将屏幕坐标当作客户区坐标使用。后来查阅资料后确认WM_LBUTTONDOWN 的 lParam 中 LOWORD 和 HIWORD 已经是相对于客户区的坐标,直接使用即可。

小组作业小结

通过本次实验,完成基于Win32 API的随机红色正方形窗口程序,加深了对Windows窗口程序设计的理解。

  1. 掌握Win32程序基础框架:WinMain完成窗口类注册、窗口创建与消息循环;WndProc窗口过程函数处理各类消息,理解Windows消息驱动的编程核心模型。
  2. 掌握GDI基础绘图流程:利用BeginPaint/EndPaint获取绘图设备环境,通过CreateSolidBrush创建画刷、SelectObject选入设备上下文,调用Rectangle绘制填充图形,使用完毕恢复、释放GDI绘图对象。
  3. 掌握鼠标消息处理:WM_LBUTTONDOWN鼠标左键消息的lParam保存鼠标坐标,通过LOWORD、HIWORD提取点击位置,结合随机数,实现每次点击生成大小不等正方形的功能。
  4. 懂得Windows绘图需要依靠WM_PAINT重绘消息,理解GDI资源要手动释放,防止产生资源泄漏。
posted @ 2026-09-24 22:03  小牙不会写代码  阅读(8)  评论(0)    收藏  举报