让我们与星光探索者一起,探索Windows吧!
下发假设您自己的窗口类的窗口过程函数均为WndProc,且您正确的按流程写了自定义的窗口程序
下方均是提供的一种处理方式的代码,并不是必须要这么做。
处理WM_CLOSE消息
WM_CLOSE消息在窗口即将终止时产生。
此消息附带的两个信息
处理窗口过程函数一个例子如下:
1 2 3 4 5 6 7 8 9 10 11 12 13
| LRESULT CALLBACK WinProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_CLOSE: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, uMsg, wParam, lParam); }
|
此外,WM_DESTROY和WM_QUIT也有退出的意思,这三个消息有什么区别呢?
WM_DESTROY在窗口销毁时产生,附带的两个信息和WM_CLOSE相同。但在WM_CLOSE可以选择决定是否销毁窗口。WM_QUIT消息在调用PostQuitMessage产生,使得GetMessage返回0。
处理WM_CREATE消息
WM_CREATE消息在窗口被创建时产生,在CreateWindow函数返回之前且窗口未显示之前产生。如果这个消息返回0,窗口将会被创建,返回-1将销毁创建的窗口。通常处理此消息时,我们初始化一些数据。
此事件附带的参数
处理窗口过程函数一个示例如下(运行本示例,您应该能看到先弹出一个消息框,再显示窗口):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| LRESULT CALLBACK WinProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_CLOSE: PostQuitMessage(0); return 0; case WM_CREATE: { LPCTSTR lpClassName = reinterpret_cast<CREATESTRUCT*>(lParam)->lpszClass; MessageBox(hwnd, TEXT("窗口创建了!"), lpClassName, MB_OK); } return 0; } return DefWindowProc(hwnd, uMsg, wParam, lParam); }
|
处理WM_SIZE消息
WM_SIZE消息将在窗口被调整大小结束后产生。窗口在第一次创建的时候理所当然会调整大小,所以至少会触发一次
此消息附带的两个信息
处理此事件的一个示例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
LRESULT CALLBACK WinProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_CLOSE: PostQuitMessage(0); FreeConsole(); return 0; case WM_CREATE: AllocConsole(); freopen("CONOUT$","w+t", stdout); case WM_SIZE: std::cout << "宽度" << LOWORD(lParam) << "高度" << HIWORD(lParam) << std::endl; } return DefWindowProc(hwnd, uMsg, wParam, lParam); }
|
运行此程序,可能的结果如下:
处理常见鼠标消息
鼠标移动,按下,松开,会产生鼠标消息。一般情况下,只有在你自己的窗口产生的鼠标消息,才会接收到,要想鼠标在哪个窗口都能处理到鼠标消息,请使用SetCapture 函数 。
鼠标在窗口移动时,产生WM_MOUSEMOVE消息消息,根据移动的快慢,产生WM_MOUSEMOVE的消息频率是不同的
鼠标左键按下时,产生WM_LBUTTONDOWN消息 ,松开时产生WM_LBUTTONUP消息。鼠标右键按下时,产生WM_RBUTTONDOWN消息,松开时产生WM_RBUTTONUP消息
消息产生均附带的两个信息
处理消息的一种示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| LRESULT CALLBACK WinProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_CLOSE: PostQuitMessage(0); FreeConsole(); return 0; case WM_CREATE: AllocConsole(); freopen("CONOUT$","w+t", stdout); case WM_LBUTTONDOWN: printf("鼠标左键按下 x:%d y: %d\n", LOWORD(lParam), HIWORD(lParam)); return 0; case WM_LBUTTONUP: printf("鼠标左键松开 x:%d y: %d\n", LOWORD(lParam), HIWORD(lParam)); return 0; case WM_MOUSEMOVE: printf("鼠标移动消息 x:%d y: %d\n", LOWORD(lParam), HIWORD(lParam)); return 0; } return DefWindowProc(hwnd, uMsg, wParam, lParam); }
|
鼠标双击消息
当鼠标左键或右键或中键双击时,并且创建窗口时使用CS_DBCLICK风格,才会产生产生鼠标双击消息。很多小伙伴可能疑惑鼠标中键在哪。实际上鼠标的那个滚轮是可以按下去的,那个就是鼠标中键了。并不是鼠标双击消息产生时,就不会产生鼠标单击消息。
以鼠标左键双击消息(WM_LBUTTONDBLCLK),产生消息的顺序是:
WM_LBUTTONDOWN, WM_LBUTTONUP, WM_LBUTTONDBLCLK, WM_LBUTTONUP
消息产生均附带的两个信息
键盘消息
当键盘的案件被按下或松开时,产生键盘事件。如WM_KEYDOWN 消息,WM_KEYUP 消息等。
消息产生均附带的两个信息
按下按键只会表明按下的是哪个按键,例如在输入大写字母A和小写字母a时,都是按下了a键,产生WM_KEYDOWN或WM_KEYUP等时没法区分。如果要得到按下按键时的ASCII值,使用WM_CHAR 消息 更加方便。
自定义消息
有的时候,我们想有自定义消息,那么我们可以使用WM_USER宏。自定义消息的格式为WM_USER + x。
以下是消息编号的范围。
范围 |
含义 |
0 到 WM_USER –1 |
保留供系统使用的消息。 |
通过 0x7FFF 进行WM_USER |
用于专用窗口类的整数消息。 |
通过0xBFFF WM_APP (0x8000) |
可供应用程序使用的消息。 |
通过 0xFFFF 进行0xC000 |
应用程序使用的字符串消息。 |
大于 0xFFFF |
系统保留。 |
示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
| #include <windows.h> #include <iostream>
#pragma comment(lib, "user32.lib") #pragma comment(lib, "gdi32.lib")
#define MY_MESSAGE WM_USER + 2
LRESULT CALLBACK WinProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
INT APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { static const TCHAR TITLE[] = TEXT("window"); static const TCHAR CLASSNAME[] = TEXT("MyStruct");
WNDCLASS wc{0}; wc.hbrBackground = (HBRUSH)GetStockObject(DKGRAY_BRUSH); wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hInstance = hInstance; wc.lpfnWndProc = WinProc; wc.lpszClassName = CLASSNAME; wc.lpszMenuName = NULL; wc.style = CS_HREDRAW | CS_VREDRAW;
RegisterClass(&wc);
HWND hwnd = CreateWindowEx( 0, CLASSNAME, TITLE, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL ); if (hwnd == NULL) { return 0; }
ShowWindow(hwnd, nCmdShow); UpdateWindow(hwnd);
MSG msg{0}; while(GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); }
return 0; }
LRESULT CALLBACK WinProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_CLOSE: PostQuitMessage(0); return 0; case WM_LBUTTONDOWN: { LRESULT nRet = SendMessage(hwnd, MY_MESSAGE, 0, 100); if (nRet == 114514) { MessageBox(hwnd, TEXT("好臭的处理方式!"), TEXT("差评"), MB_ICONWARNING); } return 0; } case MY_MESSAGE: MessageBox(hwnd, TEXT("处理我自己的消息!"), TEXT("MY_MESSAGE"), MB_OK); return 114514; } return DefWindowProc(hwnd, uMsg, wParam, lParam); }
|
运行此代码,应该在鼠标左键时弹出一个消息框显示”处理我自己的消息!”,然后显示”好臭的处理方式!”。
本期到此结束,下期看星光探索者探索使用计时器和菜单,图标,光标等资源文件