windows sdk编程 -处理鼠标输入消息
相关网站:http://edu.WINDOWS将捕捉鼠标动作并把它们发送到相关窗口。这些活动包括左、右键按下、移动、双击新式鼠标还包括滚轮消息WM_WHEEL等。WINDOWS并不像处理键盘输入那样把所有的鼠标消息都导向有输入焦点的窗口,任何鼠标经过的窗口都将接收到鼠标消息,无论有否输入焦点。另外,窗口还会接收到鼠标在非客户区移动的消息(WM_NCMOVE),但大多数的情况下我们都会将其忽略掉。 对鼠标的每一个按钮都有两个消息:WM_LBUTTONDOWN,WM_RBUTTONDOWN 。对于三键鼠标还会有WM_MBUTTONDOWN和WM_MBUTTONUP消息,当鼠标在某窗口客户区移动时,该窗口将接收到WM_MOUSEMOVE消息。一个窗口若想处理WM_LBUTTONDBCLK或 WM_RBUTTONDBCLK,那么它的窗口类必须有CS_DBLCLKS风格,否则它就会接受到一堆的按键起落(WM_XBUTTONDOWN或WM_XBUTTONUP)的消息。 对于所有的消息,窗口过程函数传入的参数lParam包含了鼠标的位置,其中底位为x坐标,高位为y坐标,这些坐标值都是相对于窗口客户区的左上角的值,wParam中则包含了鼠标按钮的状态。
#include "Windows.h"
#include "tchar.h"
HWND hWinMain;
TCHAR szClassName[] = _T("MyClass");
TCHAR szCaptionMain[] = _T("My First Window!");
TCHAR FontName[] = _T("宋体");
WNDCLASSEX stdWndClass;
WPARAM keyChar = 0x20; //0x20是空格的ascii码,保证没有按键的时候程序正常显示。
BOOL MouseClick = FALSE;
POINT hitPoint;
LRESULT CALLBACK ProcWinMain( HWND hWnd,
UINT Msg,
WPARAM wParam,
LPARAM lParam
)
{
PAINTSTRUCT stPs;
HDC hDC;
HFONT hFont,hOldFont;
switch(Msg)
{
case WM_PAINT:
{
hDC = BeginPaint(hWnd,&stPs);
hFont = CreateFont(24,16,0,0,400,0,0,0,OEM_CHARSET,OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,DEFAULT_PITCH,FontName);
hOldFont = (HFONT)SelectObject(hDC,hFont);
SetTextColor(hDC,RGB(200,200,50));
SetBkColor(hDC,RGB(0,0,255));
TextOut(hDC,0,0,(char *)&keyChar,1);
if(MouseClick)
{
TextOut(hDC,hitPoint.x,hitPoint.y,szCaptionMain,lstrlen(szCaptionMain));
}
SelectObject(hDC,hOldFont);
EndPaint(hWnd,&stPs);
}
break;
case WM_LBUTTONDOWN:
{
hitPoint.x = LOWORD(lParam);
hitPoint.y = HIWORD(lParam);
MouseClick = TRUE;
InvalidateRect(hWnd,NULL,TRUE);
}
break;
case WM_CHAR:
{
keyChar = wParam;
InvalidateRect(hWnd,NULL,TRUE);
}
break;
case WM_DESTROY:
{
PostQuitMessage(NULL);
}
break;
default:
return DefWindowProc(hWnd, Msg, wParam, lParam );
}
return 0;
}
int WINAPI WinMain( HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow
)
{
MSG stMsg;
WNDCLASSEX stdWndClass;
RtlZeroMemory(&stdWndClass, sizeof(stdWndClass));
stdWndClass.hCursor = LoadCursor(0,IDC_ARROW);
stdWndClass.cbSize = sizeof(stdWndClass);
stdWndClass.style = CS_HREDRAW|CS_VREDRAW;
stdWndClass.lpfnWndProc = ProcWinMain;
stdWndClass.hbrBackground = (HBRUSH)COLOR_WINDOW;
stdWndClass.lpszClassName = szClassName;
stdWndClass.hInstance = hInstance;
RegisterClassEx(&stdWndClass);
hWinMain = CreateWindowEx(WS_EX_CLIENTEDGE,szClassName,szCaptionMain,\
WS_OVERLAPPEDWINDOW,100,100,600,400,NULL,NULL,hInstance,NULL);
if(!hWinMain)
return 0;
ShowWindow(hWinMain,SW_SHOWNORMAL);
UpdateWindow(hWinMain);
while(GetMessage(&stMsg,NULL,0,0))
{
TranslateMessage(&stMsg);
DispatchMessage(&stMsg);
}
return stMsg.wParam;
}
分析:
case WM_LBUTTONDOWN:
{
hitPoint.x = LOWORD(lParam);
hitPoint.y = HIWORD(lParam);
MouseClick = TRUE;
InvalidateRect(hWnd,NULL,TRUE);
}
break;
窗口过程处理了WM_LBUTTONDOWN消息,当接收到该消息时,lParam中包含了相对于窗口客户区左上角的坐标,我们把它保存下来,放到一个结构体变量(POINT)中,该结构体变量的定义如下:
typedef struct tagPOINT
{
LONG x;
LONG y;
} POINT, *PPOINT;
然后我们把标志量MouseClick设为TRUE,这表明至少有一次在客户区的左键按下消息。
MouseClick = TRUE;
由于lParam是一个32位长的数,其中高、底16位分别包括了x、y坐标所以我们做一些小处理,以便保存它们。这里我们用到了两个宏LOWORD和HIWORD分别取出高16位和低16位的值。
这两个宏的定义位于WINDEF.H。定义如下:
#define LOWORD(l) ((WORD)(l))
#define HIWORD(l) ((WORD)(((DWORD)(l) >> 16) & 0xFFFF))
hitPoint.x = LOWORD(lParam);
hitPoint.y = HIWORD(lParam);
保存完坐标后我们设标志MouseClick为TRUE,这是在处理WM_PAINT时用来判断是否有鼠标左键按下消息。然后我们调用InvalidateRect()函数迫使WINDOWS重新绘制客户区。
if(MouseClick)
{
TextOut(hDC,hitPoint.x,hitPoint.y,szCaptionMain,lstrlen(szCaptionMain));
}
绘制客户区的代码首先检测MouseClick标志位,再决定是否重绘。因为我们在首次显示窗口时还没有左键按下的消息,所以我们在初始时把该标志设为FALSE,告诉WINDOWS不要重绘客户区,当有左键按下的消息时,它会在鼠标按下的位置绘制字符串。注意在调用TextOut()函数时,其关于字符串长度的参数是调用lstrlen()函数来计算的。
相关网站:http://edu.