信息学实验室作业(八)
更新: 2025/3/15 字数: 0 字 时长: 0 分钟
一、实验目的
本次实验聚焦于Win32API中定时器和鼠标处理功能的应用,旨在通过为之前绘制的图形(以房子为例)添加移动交互功能,加深对Win32API消息驱动机制、定时器操作以及鼠标事件处理的理解,提升基于Win32API进行图形化应用开发的实践能力。
二、实验环境
本次实验在Mac系统上,使用(如CrossOver、WineBottler等支持在Mac上进行Win32开发的工具)作为开发环境进行代码编写、编译和调试。
三、实现思路
- 初始化设置:在窗口创建阶段,定义全局变量来记录图形移动状态、移动偏移量和定时器ID。创建窗口并初始化相关资源,为后续操作做准备。
- 鼠标事件处理:在窗口过程函数中,针对鼠标左键按下(
WM_LBUTTONDOWN
)和右键按下(WM_RBUTTONDOWN
)消息进行处理。左键按下时,启动定时器,使图形开始移动;右键按下时,停止定时器,图形停止移动。 - 定时器处理:利用
SetTimer
函数创建定时器,设置合适的时间间隔。在定时器触发的WM_TIMER
消息处理函数中,根据移动状态更新图形的位置偏移量,并触发窗口重绘,实现图形的持续移动效果。 - 图形绘制与移动:在窗口重绘(
WM_PAINT
)消息处理函数中,根据图形移动状态和偏移量,绘制移动后的图形。在窗口销毁(WM_DESTROY
)消息处理函数中,停止定时器,释放相关资源,确保程序正常结束。
四、代码实现
cpp
#include <windows.h>
// 全局变量
BOOL bShowHouse = FALSE;
BOOL bShowName = FALSE;
const char* developerName = "叶蓝骅";
BOOL bMoving = FALSE;
int moveX = 0;
int moveY = 0;
UINT_PTR timerId = 0;
// 窗口过程函数
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_LBUTTONDOWN: {
bMoving = TRUE;
// 启动定时器,每20毫秒触发一次
timerId = SetTimer(hwnd, 1, 20, NULL);
break;
}
case WM_RBUTTONDOWN: {
bMoving = FALSE;
// 停止定时器
if (timerId) {
KillTimer(hwnd, timerId);
timerId = 0;
}
break;
}
case WM_TIMER: {
if (bMoving) {
// 向右下移动
moveX += 1;
moveY += 1;
InvalidateRect(hwnd, NULL, TRUE);
}
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 + moveX, 100 + moveY}, {100 + moveX, 200 + moveY}, {300 + moveX, 200 + moveY} };
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 + moveX, 200 + moveY, 300 + moveX, 300 + moveY);
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 + moveX, 50 + moveY, 270 + moveX, 150 + moveY);
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:
if (timerId) {
KillTimer(hwnd, timerId);
}
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;
}
五、代码解释
- 全局变量:
bShowHouse
和bShowName
用于控制房子图形和开发者姓名的显示;bMoving
记录图形是否正在移动;moveX
和moveY
存储图形在x和y方向的移动偏移量;timerId
保存定时器的标识符。 - 窗口过程函数(
WndProc
):WM_CREATE
:窗口创建时,创建“显示图形”“清除图形”“显示姓名”三个按钮。WM_COMMAND
:根据按钮ID处理按钮点击事件,更新bShowHouse
和bShowName
的值,触发窗口重绘。WM_LBUTTONDOWN
:鼠标左键按下时,将bMoving
设为TRUE
,并启动定时器,设定定时器ID为1,时间间隔为20毫秒。WM_RBUTTONDOWN
:鼠标右键按下时,将bMoving
设为FALSE
,若定时器正在运行,则停止定时器。WM_TIMER
:定时器触发时,若bMoving
为TRUE
,则使moveX
和moveY
分别增加1,实现图形向右下移动,并触发窗口重绘。WM_PAINT
:重绘窗口时,若bShowHouse
为TRUE
,根据moveX
和moveY
的值绘制移动后的房子图形;若bShowName
为TRUE
,显示开发者姓名。WM_DESTROY
:窗口销毁时,停止定时器,发送退出消息,结束程序。
- 主函数(
WinMain
):注册窗口类,设置窗口过程函数、实例句柄、类名和背景颜色等;创建窗口并显示;进入消息循环,处理窗口消息。
六、编译与运行
- 编译:将代码保存为
.cpp
文件,在开发环境中进行编译。确保开发环境已正确配置Win32API相关的头文件和库文件路径。编译过程中,根据错误提示信息修改代码中的语法错误和逻辑错误,直至编译成功。 - 运行:编译成功后运行程序。程序启动后,窗口中显示三个按钮。点击“显示图形”按钮,房子图形出现;按下鼠标左键,房子开始向右下移动;按下鼠标右键,房子停止移动。点击“显示姓名”按钮,窗口中显示开发者姓名;点击“清除图形”按钮,房子图形和姓名消失。
七、实验总结
通过本次实验,成功实现了在Win32API环境下,利用定时器和鼠标事件为图形添加交互功能。在实验过程中,深入理解了定时器和鼠标消息的处理机制,以及如何通过消息驱动实现图形的动态效果和用户交互。遇到了定时器启动和停止的时机把握、图形绘制坐标计算等问题,通过调试和查阅资料解决了这些问题,提升了编程和调试能力。后续可以进一步拓展功能,如增加图形移动速度的控制、改变图形移动方向的更多操作方式等,以丰富应用的交互体验。