Skip to content

信息学实验室作业(七)

更新: 2025/3/15 字数: 0 字 时长: 0 分钟

一、实验目的

本次实验旨在运用Win32 API在Mac系统开发环境中创建一个具备图形绘制和用户交互功能的应用程序。通过在窗口中绘制房子图案,并利用按钮实现图形显示、清除和显示开发者姓名等操作,深入理解和掌握Win32 API在窗口编程、消息处理、图形绘制以及控件使用方面的应用。

二、实验环境

本次实验在Mac系统上,借助(如CrossOver、WineBottler等支持在Mac上进行Win32开发的工具)作为开发环境进行开发。

三、实现思路

  1. 项目创建与初始化:在选定的开发工具中创建Win32项目,选择空项目模板,添加源文件。在WinMain函数中完成窗口类的注册和窗口的创建,为后续操作奠定基础。
  2. 控件创建:在窗口创建过程中,通过CreateWindow函数创建三个按钮控件,分别用于显示图形、清除图形和显示开发者姓名。每个按钮都指定了相应的文本、位置、大小和唯一的ID标识。
  3. 图形绘制:在WM_PAINT消息处理函数中,根据标志变量的状态绘制房子图形。利用CreatePenCreateSolidBrush函数创建画笔和画刷,设置不同的颜色来绘制屋顶(红色)、墙壁(蓝色)和烟囱(绿色)。通过PolygonRectangle等绘图函数完成图形的绘制。
  4. 按钮事件处理:在WM_COMMAND消息处理函数中,根据按钮的ID判断用户点击的是哪个按钮。针对不同按钮的点击,修改相应的标志变量,然后调用InvalidateRect函数触发窗口重绘,以实现对应的功能。
  5. 开发者姓名显示:当点击显示开发者姓名的按钮时,在WM_PAINT消息处理函数中,通过TextOut函数在窗口指定位置显示开发者姓名“叶蓝骅”。

四、代码实现

cpp
#include <windows.h>

// 全局变量,用于控制图形显示和姓名显示
BOOL bShowHouse = FALSE;
BOOL bShowName = FALSE;
const char* developerName = "叶蓝骅";

// 窗口过程函数,处理窗口消息
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
    switch (msg) {
    case WM_CREATE: {
        // 创建显示图形按钮
        CreateWindow("BUTTON", "显示图形", WS_VISIBLE | WS_CHILD, 10, 10, 100, 30, hwnd, (HMENU)1, NULL, NULL);
        // 创建清除图形按钮
        CreateWindow("BUTTON", "清除图形", WS_VISIBLE | WS_CHILD, 120, 10, 100, 30, hwnd, (HMENU)2, NULL, NULL);
        // 创建显示姓氏按钮
        CreateWindow("BUTTON", "显示姓名", WS_VISIBLE | WS_CHILD, 230, 10, 100, 30, hwnd, (HMENU)3, NULL, NULL);
        break;
    }
    case WM_COMMAND: {
        switch (LOWORD(wParam)) {
        case 1:
            bShowHouse = TRUE;
            bShowName = FALSE;
            // 触发窗口重绘
            InvalidateRect(hwnd, NULL, TRUE);
            break;
        case 2:
            bShowHouse = FALSE;
            bShowName = FALSE;
            // 触发窗口重绘
            InvalidateRect(hwnd, NULL, TRUE);
            break;
        case 3:
            bShowHouse = FALSE;
            bShowName = TRUE;
            // 触发窗口重绘
            InvalidateRect(hwnd, NULL, TRUE);
            break;
        }
        break;
    }
    case WM_PAINT: {
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(hwnd, &ps);

        if (bShowHouse) {
            // 创建红色画笔和画刷用于绘制屋顶
            HPEN hRedPen = CreatePen(PS_SOLID, 2, RGB(255, 0, 0));
            HBRUSH hRedBrush = CreateSolidBrush(RGB(255, 0, 0));
            SelectObject(hdc, hRedPen);
            SelectObject(hdc, hRedBrush);
            // 定义屋顶的顶点坐标
            POINT roofPoints[] = { {200, 100}, {100, 200}, {300, 200} };
            // 绘制屋顶
            Polygon(hdc, roofPoints, 3);
            // 删除画笔和画刷
            DeleteObject(hRedPen);
            DeleteObject(hRedBrush);

            // 创建蓝色画笔和画刷用于绘制墙壁
            HPEN hBluePen = CreatePen(PS_SOLID, 2, RGB(0, 0, 255));
            HBRUSH hBlueBrush = CreateSolidBrush(RGB(0, 0, 255));
            SelectObject(hdc, hBluePen);
            SelectObject(hdc, hBlueBrush);
            // 绘制墙壁
            Rectangle(hdc, 100, 200, 300, 300);
            // 删除画笔和画刷
            DeleteObject(hBluePen);
            DeleteObject(hBlueBrush);

            // 创建绿色画笔和画刷用于绘制烟囱
            HPEN hGreenPen = CreatePen(PS_SOLID, 2, RGB(0, 255, 0));
            HBRUSH hGreenBrush = CreateSolidBrush(RGB(0, 255, 0));
            SelectObject(hdc, hGreenPen);
            SelectObject(hdc, hGreenBrush);
            // 绘制烟囱
            Rectangle(hdc, 250, 50, 270, 150);
            // 删除画笔和画刷
            DeleteObject(hGreenPen);
            DeleteObject(hGreenBrush);
        }

        if (bShowName) {
            // 设置文本颜色为黑色
            SetTextColor(hdc, RGB(0, 0, 0));
            // 设置文本背景模式为透明
            SetBkMode(hdc, TRANSPARENT);
            // 在窗口中显示开发者姓名
            TextOut(hdc, 200, 200, developerName, strlen(developerName));
        }

        EndPaint(hwnd, &ps);
        break;
    }
    case WM_DESTROY:
        // 发送退出消息,结束程序
        PostQuitMessage(0);
        break;
    default:
        // 调用默认的窗口过程处理其他消息
        return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    return 0;
}

// 主函数,程序入口
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) {
    // 定义窗口类
    WNDCLASS wc = { 0 };
    wc.lpfnWndProc = WndProc;
    wc.hInstance = hInstance;
    wc.lpszClassName = "HouseDrawing";
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    // 注册窗口类
    RegisterClass(&wc);

    // 创建窗口
    HWND hwnd = CreateWindow(wc.lpszClassName, "房子绘制", WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, 600, 400, NULL, NULL, hInstance, NULL);

    // 显示窗口
    ShowWindow(hwnd, iCmdShow);
    // 更新窗口
    UpdateWindow(hwnd);

    // 消息循环
    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return msg.wParam;
}

五、代码解释

  1. 全局变量bShowHousebShowName是布尔型全局变量,分别用于控制房子图形和开发者姓名是否显示。developerName是一个常量字符串,存储开发者姓名“叶蓝骅”。
  2. WndProc函数
    • WM_CREATE消息处理:在窗口创建时,使用CreateWindow函数创建三个按钮,每个按钮的参数包括按钮类型、显示文本、窗口样式、位置、大小、父窗口句柄、菜单ID等。
    • WM_COMMAND消息处理:通过LOWORD(wParam)获取触发消息的控件ID。根据不同的ID,修改bShowHousebShowName的值,并调用InvalidateRect函数,该函数会向窗口发送WM_PAINT消息,触发窗口重绘。
    • WM_PAINT消息处理:首先通过BeginPaint获取设备上下文hdc,根据bShowHousebShowName的值进行相应绘制。若bShowHouse为真,创建不同颜色的画笔和画刷绘制房子的各个部分;若bShowName为真,设置文本颜色和背景模式后,使用TextOut函数显示开发者姓名。最后通过EndPaint结束绘制。
    • WM_DESTROY消息处理:当窗口接收到销毁消息时,调用PostQuitMessage函数,向消息队列发送退出消息,结束程序的消息循环。
    • 默认情况:对于其他未处理的消息,调用DefWindowProc函数,由系统默认的窗口过程进行处理。
  3. WinMain函数
    • 窗口类定义与注册:定义WNDCLASS结构体wc,设置窗口过程函数、实例句柄、类名和背景颜色等属性,然后使用RegisterClass函数注册窗口类。
    • 窗口创建与显示:调用CreateWindow函数创建窗口,指定窗口类名、标题、样式、位置、大小等参数。创建完成后,通过ShowWindow显示窗口,并使用UpdateWindow更新窗口内容。
    • 消息循环:通过GetMessage函数从消息队列中获取消息,使用TranslateMessageDispatchMessage函数进行消息转换和分发,直到获取到退出消息,结束程序。

六、编译与运行

  1. 编译:将上述代码保存为.cpp文件,在Mac系统的开发工具中进行编译。由于是在Mac系统上模拟Win32开发环境,可能需要特别注意开发工具的设置,如确保正确链接Win32库文件等。编译过程中,若出现错误,根据错误提示信息仔细检查代码和开发环境配置,进行相应修改,直至编译成功。
  2. 运行:编译成功后,运行生成的可执行文件。程序启动后,会弹出一个窗口,窗口中包含三个按钮。点击“显示图形”按钮,窗口中会绘制出带有红色屋顶、蓝色墙壁和绿色烟囱的房子图形;点击“清除图形”按钮,窗口中的图形会被清除;点击“显示姓名”按钮,窗口中会显示“叶蓝骅”。

七、实验总结

通过本次在Mac系统上基于Win32 API的开发实验,成功实现了窗口绘图和用户交互功能。在实验过程中,不仅加深了对Win32 API相关知识的理解和运用,还掌握了在Mac系统中搭建Win32开发环境的方法。遇到了开发环境配置、图形绘制细节等问题,通过查阅资料、调试代码,逐步解决了这些问题,提升了自己的问题解决能力。后续可以进一步优化程序,如改进图形绘制的细节、增加更多交互功能等,以提高程序的实用性和用户体验。