处理与鼠标交互相关的事件,比如移动、点击和滚动等。例如:
在 Windows 程序中,消息处理的流程是通过一个称为消息循环
的结构,结合窗口过程(WndProc)
来完成的。这个窗口过程是一个由开发者实现的函数,用于响应和处理发送到窗口的消息。以下是详细的消息处理流程:
WinMain
函数中初始化应用程序,并进入消息循环。GetMessage
函数从消息队列中检索消息。这个函数会阻塞,直到队列中有消息。TranslateMessage
函数会对这些消息进行适当处理,比如生成字符消息(WM_CHAR)。DispatchMessage
函数,将消息传递给相应窗口的窗口过程进行处理。WndProc
)。switch
语句(或类似的结构)来识别消息类型,并对每种类型的消息做出响应。WM_PAINT
消息会导致窗口重新绘制其内容,WM_DESTROY
消息会触发清理资源的操作。DefWindowProc
函数,这是系统提供的默认窗口过程,用于处理标准动作。WM_CLOSE
消息会被发送到窗口过程。WM_CLOSE
。如果程序需要确认用户的关闭请求(比如,询问是否保存数据),就可以在这里实现。DestroyWindow
函数来销毁窗口。DestroyWindow
调用后,WM_DESTROY 消息会被发送到窗口过程。在这里,窗口过程通常会进行资源的最终清理。WM_DESTROY
的处理结束后,窗口过程会调用 PostQuitMessage 函数,这会放置 WM_QUIT
消息到消息队列。GetMessage```检索到
WM_QUIT`` 消息时,它会返回 0,导致消息循环结束,程序随之退出。WM_CLOSE
:
WM_DESTROY
WM_CLOSE
可以视为关闭过程的开始,是一个可以被程序控制和决定的阶段,而 WM_DESTROY
则标志着关闭过程的终结,窗口即将被销毁,此时应进行最后的清理工作。调用 CreateWindowEx() 函数会触发一系列窗口消息,这些消息涉及到窗口的创建和显示过程。以下是在调用 CreateWindowEx() 时通常会触发的主要消息,按照它们出现的典型顺序列出:
在 Visual Studio 中使用 消息变量名,wm
来在监视窗口中查看 Windows 消息名称是一个非常方便的功能,它可以帮助开发者直观地理解当前处理的消息类型。
OutputDebugString
是 Windows API 中的一个调试辅助函数,它用于将字符串信息发送到调试器的输出窗口。这对于开发和调试 Windows 应用程序非常有用,尤其是当你需要在运行时监控程序的内部状态或行为时。case WM_LBUTTONDOWN:
{
int x = (int)(short)LOWORD(lParam); // 新的 X 坐标
int y = (int)(short)HIWORD(lParam); // 新的 Y 坐标
char buffer[100];
//将格式化的数据写入到buffer缓冲区中
wsprintf(buffer, "你点击了,x坐标:%d, y坐标:%d\n", x, y);
//输出调试信息
OutputDebugString(buffer);
return 0;
}
OutputDebugString
输出的调试信息DebugView
来捕捉由 OutputDebugString 输出的调试信息。点击下载#include
//显示错误信息
void ShowErrorMessage();
//5.消息处理
LRESULT CALLBACK WndProc(
HWND hwnd,
UINT msg,
WPARAM wParam,
LPARAM lParam
)
{
// 根据消息类型进行分支处理
switch (msg)
{
case WM_CREATE:
{
OutputDebugString("WM_CREATE\n");
return 0;
}
case WM_CLOSE:
{
//询问是否关闭窗口
int id = MessageBox(NULL, "你确定关闭窗口吗", "WM_CLOSE", MB_YESNO);
if (id == IDYES)
{
DestroyWindow(hwnd);
}
return 0;
}
case WM_DESTROY:
{
OutputDebugString("WM_DESTROY\n");
PostQuitMessage(0);
return 0;
}
case WM_MOVE: //窗口移动
{
int x = (int)(short)LOWORD(lParam); // 新的 X 坐标
int y = (int)(short)HIWORD(lParam); // 新的 Y 坐标
char buffer[100];
wsprintf(buffer,"窗口移动到了:x坐标:%d, y坐标:%d\n",x,y);
OutputDebugString(buffer);
break;
}
case WM_LBUTTONDOWN: //鼠标左键按下
{
int x1 = (int)(short)LOWORD(lParam); // 新的 X 坐标
int y1 = (int)(short)HIWORD(lParam); // 新的 Y 坐标
char buffer1[100];
wsprintf(buffer1, "鼠标点击了,x坐标:%d, y坐标:%d\n", x1, y1);
OutputDebugString(buffer1);
return 0;
}
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
int WINAPI WinMain(
HINSTANCE hInstance, // 当前实例的句柄
HINSTANCE hPrevInstance, // 前一个实例的句柄,现在总是为 NULL
LPSTR lpCmdLine, // 命令行参数的字符串
int nCmdShow // 指示程序窗口应如何被显示
)
{
//1.注册窗口
char MyWindowClassName[] = "MyWindowClass"; //窗口类名
WNDCLASSEX wc = { 0 };
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_VREDRAW | CS_HREDRAW; //
wc.lpfnWndProc = WndProc; //窗口过程函数(窗口回调函数->处理消息)
wc.hInstance = hInstance;
wc.hIcon = NULL; //图标
wc.hCursor = NULL; //光标
wc.hbrBackground = CreateSolidBrush(RGB(0, 255, 0)); //窗口背景颜色刷子
wc.lpszMenuName = NULL; //菜单名称
wc.lpszClassName = MyWindowClassName; //窗口类名
if (RegisterClassEx(&wc) == 0)
{
ShowErrorMessage();
return 0;
}
//2.创建窗口
char MyWindowName[] = "MyWindowClass"; //窗口名称
HWND hwnd = CreateWindowEx(
0,
MyWindowClassName,
MyWindowName,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL
);
if (hwnd == NULL)
{
ShowErrorMessage();
return 0;
}
//3.显示更新窗口
ShowWindow(hwnd, SW_SHOWNORMAL);
UpdateWindow(hwnd);
//4.消息循环(消息队列)
MSG msg = {};
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
void ShowErrorMessage()
{
char szErrorMessage[512]; // 错误消息缓冲区
DWORD dwResult = FormatMessage(
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
GetLastError(),
0,
szErrorMessage,
sizeof(szErrorMessage) / sizeof(WCHAR),
NULL);
if (dwResult > 0) {
// 使用 MessageBox 显示错误消息
MessageBox(NULL, szErrorMessage, "Error", MB_OK | MB_ICONERROR);
}
else {
// 如果无法获取错误消息,使用 MessageBox 显示一个失败通知
MessageBox(NULL, "Failed to retrieve the error message.", "Error", MB_OK | MB_ICONERROR);
}
}