在Win32环境下,处理任何消息都很简单,消息循环会保证任何发生在进程内的消息都会送到消息处理回调函数中处理,我们只需在那个swtich
结构中case我们感兴趣的消息代码(以WM_开头的一系列宏),然后编程处理它就可以了。
每次收到鼠标消息后,通过消息参数 WPARAM 和
LPARAM,我们可以进一步获取到鼠标指针位置和一个组合键状态,参考WinProcs.c中注释。
本例中介绍了以WM_L开头的几个消息,是鼠标左键动作消息,同理WM_R开头的为鼠标右键动作消息;本例中介绍的鼠标消息均为“客户区”鼠标消息,还有WM_NC开头的消息,是系统区(标题栏,框架边框等区域)鼠标消息,大家可以自行学习。
这里我们要注意一点,即消息处理和绘图之间的关系。
对于 Win32 应用程序来说,绘制本身也是一个消息
(WM_PAINT),窗体只有接收到这个消息,才能进行绘图。例如,我们收到一个鼠标键按下消息(WM_LBUTTONDOWN),我们写了一个处理该消息的函数,那能不能直接在该函数中对窗体进行绘图呢?答案是否定的。我们只能在这个函数中想办法记录一些变量,然后等到
WM_PAINT 消息来到时,再根据这些变量的值进行绘图。
比如说老师在讲台上讲课,这时一个学生提问,老师就得针对学生提问这一消息进行处理,并输出处理结果,如果老师需要进一步在黑板上书写,那也是老师根据这次提问消息的结果决定要在黑板上输出,和提问消息本身没有关系。
总之牢记一点,在一般情况下,除了绘图外的任何其他消息,都不应该直接操作绘图设备上下文句柄。
当我们用鼠标在Windows中滑动,点击的时候,硬件驱动会向 Windows
报告鼠标指针的位置和按键点击情况,如果鼠标指针的位置恰好处于我们自行开发的窗体应用程序之上,则我们创建的窗口就会收到若干条消息,如:
- WM_MOUSEMOVE
- WM_LBUTTONDOWN
- WM_LBUTTONUP
- WM_LBUTTONDBLCLK
等,并通过消息参数进一步获取到鼠标的指针位置和状态。
程序清单:
h文件 |
c文件 |
说明 |
无 |
Main.c |
包含主函数,启动主窗体 |
WinClasses.h |
WinClasses.c |
包含注册窗体类的代码 |
WinProcs.h |
WinProcs.c |
包含窗体消息处理函数代码 |
WinMainMsgProc.h |
WinMainMsgProc.c |
包含消息处理代码 |
1、Main.c
- #include <tchar.h>
- #include <stdio.h>
- #include <windows.h>
-
- #include "WinClasses.h"
-
- int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
- {
- TCHAR szError[BUFSIZ] = _T("");
- HWND hWnd = NULL;
- MSG msg;
-
- ZeroMemory(&msg, sizeof(msg));
-
- if (RegistMainWinClass(hInstance) == 0)
- {
- _stprintf_s(szError, BUFSIZ,
- _T("出现错误,无法注册窗口,错误代码:%d。"), GetLastError());
- MessageBox(NULL, szError, _T("错误"), MB_OK | MB_ICONERROR);
- }
- else
- {
- hWnd = CreateWindowEx(0, MAIN_CLASSNAME,
- _T("Hello World"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,
- 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL
- );
-
- if (hWnd == NULL)
- {
- _stprintf_s(szError, BUFSIZ, _T("出现错误,无法创建窗口,错误代码:%d。"), GetLastError());
- MessageBox(NULL, szError, _T("错误"), MB_OK | MB_ICONERROR);
- }
- else
- {
- ShowWindow(hWnd, nCmdShow);
- UpdateWindow(hWnd);
-
- while (GetMessage(&msg, NULL, 0, 0))
- {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
- }
- }
- return msg.wParam;
- }
2.1 WinClasses.h
- #pragma once
- #include <windows.h>
-
- #define MAIN_CLASSNAME _T("KeyMessages")
-
- ATOM WINAPI RegistMainWinClass(HINSTANCE hIns);
2.2 WinClasses.c
- #include <tchar.h>
-
- #include "WinClasses.h"
- #include "WinProcs.h"
-
- ATOM WINAPI RegistMainWinClass(HINSTANCE hIns)
- {
- WNDCLASSEX wcex;
- ZeroMemory(&wcex, sizeof(wcex));
-
- wcex.cbSize = sizeof(wcex);
-
-
- wcex.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
- wcex.lpfnWndProc = WndMainProc;
- wcex.hInstance = hIns;
- wcex.hIcon = LoadIcon(hIns, MAKEINTRESOURCE(IDI_APPLICATION));
- wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
- wcex.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
- wcex.lpszClassName = MAIN_CLASSNAME;
- wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
-
- return RegisterClassEx(&wcex);
- }
3.1 WinProcs.h
- #pragma once
- #include <windows.h>
-
- LRESULT CALLBACK WndMainProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
3.2 WinProcs.c
- #include <tchar.h>
-
- #include "WinProcs.h"
- #include "WinMainMsgProc.h"
-
- LRESULT CALLBACK WndMainProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
- {
- HDC hDC = NULL;
- PAINTSTRUCT ps;
-
- LRESULT lReturn = 0L;
- switch (message) {
- case WM_CREATE:
- RedrawWindow(hWnd, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASE);
- break;
- case WM_PAINT:
- hDC = BeginPaint(hWnd, &ps);
- OnRedrawWindow(hDC);
- EndPaint(hWnd, &ps);
- break;
- case WM_MOUSEMOVE:
-
-
- OnMouseMove(hWnd, LOWORD(lParam), HIWORD(lParam), (int)wParam);
- break;
- case WM_LBUTTONDOWN:
- OnMouseLButtonDown(hWnd, LOWORD(lParam), HIWORD(lParam), (int)wParam);
- break;
- case WM_LBUTTONUP:
- OnMouseLButtonUp(hWnd, LOWORD(lParam), HIWORD(lParam), (int)wParam);
- break;
- case WM_LBUTTONDBLCLK:
- OnMouseLButtonDoubleClick(hWnd, LOWORD(lParam), HIWORD(lParam), (int)wParam);
- break;
- case WM_CLOSE:
- if (MessageBox(hWnd, _T("是否要退出应用程序?"), _T("提示"), MB_YESNO | MB_ICONQUESTION) == IDYES)
- DestroyWindow(hWnd);
- break;
- case WM_DESTROY:
- PostQuitMessage(0);
- break;
- default:
- lReturn = DefWindowProc(hWnd, message, wParam, lParam);
- }
- return lReturn;
- }
4.1 WinMainMsgProc.h
- #pragma once
- #include <Windows.h>
-
-
- void WINAPI OnRedrawWindow(HDC hDC);
-
-
- void WINAPI OnMouseMove(HWND hWnd, int x, int y, int nMark);
-
-
- void WINAPI OnMouseLButtonDown(HWND hWnd, int x, int y, int nMark);
-
-
- void WINAPI OnMouseLButtonUp(HWND hWnd, int x, int y, int nMark);
-
-
- void WINAPI OnMouseLButtonDoubleClick(HWND hWnd, int x, int y, int nMark);
4.2
WinMainMsgProc.c
- #include <tchar.h>
- #include <stdio.h>
-
- #include "WinMainMsgProc.h"
-
- #define LEFT_SIDE 20
- #define TOP_SIDE 10
-
-
- typedef enum
- {
- Nothing = 0,
- BtnDown = 1,
- BtnUp = 2,
- BtnDBL = 3
- } BUTON_STATUS;
-
-
- static POINT g_pntMouse = {0, 0};
-
-
-
-
-
-
-
-
- static int g_nMark = 0;
-
-
- static POINT g_pntL = {0, 0};
-
-
-
-
-
-
- static int g_nMarkL = 0;
-
-
- static BUTON_STATUS g_bsL = Nothing;
-
-
-
-
-
-
-
-
- __inline BOOL IsStringEmpty(CONST LPCTSTR lpszString)
- {
- return lpszString[0] == _T(‘\0‘);
- }
-
-
-
-
-
- void WINAPI OnRedrawWindow(HDC hDC)
- {
- int nTop = TOP_SIDE;
- int nLen = 0;
- TCHAR szBuffer[BUFSIZ] = _T("");
- HFONT hOldFont = NULL;
- COLORREF cOldFont = 0;
-
-
- hOldFont = SelectObject(hDC, GetStockObject(DEFAULT_GUI_FONT));
-
-
- cOldFont = SetTextColor(hDC, RGB(220, 10, 10));
-
-
- nLen = _stprintf_s(szBuffer, BUFSIZ, _T("鼠标 X 坐标 %d;Y 坐标 %d。"), g_pntMouse.x, g_pntMouse.y);
-
-
- TextOut(
- hDC,
- LEFT_SIDE,
- nTop,
- szBuffer,
- nLen
- );
-
-
- if (g_nMark != 0)
- {
-
- nTop += 20;
- _tcscpy_s(szBuffer, BUFSIZ, _T(""));
-
-
- if (g_nMark & MK_CONTROL)
- _tcscat_s(szBuffer, BUFSIZ, _T("CTRL 键被按下"));
-
- if (g_nMark & MK_LBUTTON)
- {
- if (!IsStringEmpty(szBuffer))
- _tcscat_s(szBuffer, BUFSIZ, _T(";"));
- _tcscat_s(szBuffer, BUFSIZ, _T("鼠标 左 键被按下"));
- }
-
- if (g_nMark & MK_RBUTTON)
- {
- if (!IsStringEmpty(szBuffer))
- _tcscat_s(szBuffer, BUFSIZ, _T(";"));
- _tcscat_s(szBuffer, BUFSIZ, _T("鼠标 右 键被按下"));
- }
-
- if (g_nMark & MK_SHIFT)
- {
- if (!IsStringEmpty(szBuffer))
- _tcscat_s(szBuffer, BUFSIZ, _T(";"));
- _tcscat_s(szBuffer, BUFSIZ, _T("SHIFT 键被按下"));
- }
- _tcscat_s(szBuffer, BUFSIZ, _T("。"));
-
-
- SetTextColor(hDC, RGB(0, 200, 0));
- TextOut(hDC, LEFT_SIDE, nTop, szBuffer, _tcslen(szBuffer));
- }
-
-
- if (g_bsL > Nothing)
- {
-
-
- _stprintf_s(szBuffer, BUFSIZ,
- g_bsL == BtnDBL ? _T("LDBL (%d, %d)") :
- (g_bsL == BtnDown ? _T("LD (%d, %d)") : _T("LU (%d, %d)")),
- g_pntL.x, g_pntL.y
- );
-
-
- if (g_nMarkL & MK_CONTROL)
- _tcscat_s(szBuffer, BUFSIZ, _T(" CTRL"));
-
- if (g_nMarkL & MK_SHIFT)
- _tcscat_s(szBuffer, BUFSIZ, _T(" SHIFT"));
-
-
- SetTextColor(hDC, g_bsL == BtnDBL ? RGB(0, 200, 200) : (g_bsL == BtnDown ? RGB(0, 0, 200) : RGB(200, 200, 0)));
-
-
- TextOut(hDC, g_pntL.x + 20, g_pntL.y, szBuffer, _tcslen(szBuffer));
-
-
- g_bsL = Nothing;
- }
-
- SelectObject(hDC, hOldFont);
- SetTextColor(hDC, cOldFont);
- }
-
-
-
-
-
-
-
-
- void WINAPI OnMouseMove(HWND hWnd, int x, int y, int nMark)
- {
- g_pntMouse.x = x;
- g_pntMouse.y = y;
- g_nMark = nMark;
- RedrawWindow(hWnd, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASE );
- }
-
-
-
-
-
-
-
-
- void WINAPI OnMouseLButtonDown(HWND hWnd, int x, int y, int nMark)
- {
- g_pntL.x = x;
- g_pntL.y = y;
- g_nMarkL = nMark;
- g_bsL = BtnDown;
- RedrawWindow(hWnd, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASE );
- }
-
-
-
-
-
-
-
-
- void WINAPI OnMouseLButtonUp(HWND hWnd, int x, int y, int nMark)
- {
- g_pntL.x = x;
- g_pntL.y = y;
- g_nMarkL = nMark;
- g_bsL = BtnUp;
- RedrawWindow(hWnd, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASE );
- }
-
-
-
-
-
-
-
-
- void WINAPI OnMouseLButtonDoubleClick(HWND hWnd, int x, int y, int nMark)
- {
- g_pntL.x = x;
- g_pntL.y = y;
- g_nMarkL = nMark;
- g_bsL = BtnDBL;
- RedrawWindow(hWnd, NULL, NULL, RDW_INVALIDATE | RDW_UPDA