windows程序设计(14):鼠标消息详解

关于鼠标的一些细节知识:

通常,我们发消息时,都是对一个特定的窗口,但是对于鼠标消息却不然:只要鼠标跨越窗口或者在某窗口中按下鼠标按键,那么窗口消息处理程序就会收到鼠标消息,而不管该窗口是否活动或者是否拥有输入焦点。鼠标消息一个有21种:10个显示区域消息,11个非显示区域消息

显示区域鼠标消息

当鼠标移过窗口的显示区域时,窗口消息处理程序收到WM_MOUSEMOVE消息。

当在窗口的显示区域中按下或者释放一个鼠标按键时,窗口消息处理程序会接收到下面这些消息:

按下

释放

按下(双键)

WM_LBUTTONDOWN

WM_LBUTTONUP

WM_LBUTTONDBLCLK

WM_MBUTTONDOWN

WM_MBUTTONUP

WM_MBUTTONDBLCLK

WM_RBUTTONDOWN

WM_RBUTTONUP

WM_RBUTTONDBLCLK

只有对三键鼠标,窗口消息处理程序才会收到MBUTTON消息。

对于这些消息,其lParam值均含有鼠标的位置:低字字节为x坐标,高字节为y坐标,这两个坐标是相对于窗口显示区域左上角的位置。您可以用LOWORD和HIWORD宏来提取这些值:

x = LOWORD (lParam) ;       
y = HIWORD (lParam)  ;

wParam的值指示鼠标按键以及Shift和Ctrl键的状态:

MK_LBUTTON

按下左键

MK_MBUTTON

按下中键

MK_RBUTTON

按下右键

MK_SHIFT

按下Shift键

MK_CONTROL

按下Ctrl键

举个例子,如果收到了WM_LBUTTONDOWN且wparam & MK_SHIFT为真,则说明左键按下时也按下了Shift键。

这里要强调一下:

1.WM_MOUSEMOVE消息:当您把鼠标移过窗口的显示区域时,Windows并不为鼠标的每个可能的图素位置都产生一个WM_MOUSEMOVE消息。您的程序接收到WM_MOUSEMOVE消息的次数,依赖于鼠标硬件,以及您的窗口消息处理程序在处理鼠标移动消息时的速度。换句话说,Windows不能用未处理的WM_MOUSEMOVE消息来填入消息队列。

2.对于WM_LBUTTONDOWN和WM_LBUTTONUP消息可能只收到一个!比如在一个窗口中按下鼠标按键,然后移动到使用者窗口释放它,就会出现这种情况。类似的情况,当鼠标按键在另一个窗口中被释放时,窗口消息处理程序只能接收到WM_LBUTTONDOWN消息,而没有相应的WM_LBUTTONUP消息。

3.关于双击鼠标:双击的间隔在控制面板里可以设置。但是是否需要相应“双击”则是我们自己写的:在注册窗口时,必须在窗口风格中包含CS_DBLCLKS标识符。这样当你双击时,系统会收到:

WM_LBUTTONDOWN

WM_LBUTTONUP

WM_LBUTTONDBLCLK

WM_LBUTTONUP

否则,只会收到:

WM_LBUTTONDOWN

WM_LBUTTONUP

WM_LBUTTONDOWN

WM_LBUTTONUP


看一个例子程序:

/*--------------------------------------------------
   CONNECT.C -- Connect-the-Dots Mouse Demo Program
			 (c) Charles Petzold, 1998
  --------------------------------------------------*/

#include 

#define MAXPOINTS 1000

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
				PSTR szCmdLine, int iCmdShow)
{
	 
	static TCHAR	szAppName[] = TEXT ("Connect") ;
	HWND			hwnd ;
	MSG				msg ;
	WNDCLASS		wndclass ;
	
	wndclass.style			= CS_HREDRAW | CS_VREDRAW ;
	wndclass.lpfnWndProc	= WndProc ;
	wndclass.cbClsExtra		= 0 ;
	wndclass.cbWndExtra		= 0 ;
	wndclass.hInstance		= hInstance ;
	wndclass.hIcon			= LoadIcon (NULL, IDI_APPLICATION) ;
	wndclass.hCursor		= LoadCursor (NULL, IDC_ARROW) ;
	wndclass.hbrBackground	= (HBRUSH) GetStockObject (WHITE_BRUSH) ;
	wndclass.lpszMenuName	= NULL ;
	wndclass.lpszClassName	= szAppName ;
	
	if (!RegisterClass (&wndclass))
	{
		MessageBox (NULL, TEXT ("Program requires Windows NT!"), 
				  szAppName, MB_ICONERROR) ;
		return 0 ;
	}
	
	hwnd = CreateWindow (szAppName, TEXT ("Connect-the-Points Mouse Demo"),
					 WS_OVERLAPPEDWINDOW,
					 CW_USEDEFAULT, CW_USEDEFAULT,
					 CW_USEDEFAULT, CW_USEDEFAULT,
					 NULL, NULL, hInstance, NULL) ;
	
	ShowWindow (hwnd, iCmdShow) ;
	UpdateWindow (hwnd) ;
	
	while (GetMessage (&msg, NULL, 0, 0))
	{
		TranslateMessage (&msg) ;
		DispatchMessage (&msg) ;
	}
	return msg.wParam ;
}

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	static POINT	pt[MAXPOINTS] ;
	static int		iCount ;
	HDC				hdc ;
	int				i, j ;
	PAINTSTRUCT		ps ;

	switch (message)
	{
	case WM_LBUTTONDOWN:
		iCount = 0 ;
		InvalidateRect (hwnd, NULL, TRUE) ;
		return 0 ;
		
	case WM_MOUSEMOVE:
		//是否按下了左键且收到的点数不到1000
		if (wParam & MK_LBUTTON && iCount < 1000)
		{
			//记录鼠标位置并在最后iCount+1
			pt[iCount  ].x = LOWORD (lParam) ;
			pt[iCount++].y = HIWORD (lParam) ;
			
			hdc = GetDC (hwnd) ;
			//在指定的位置设置指定颜色的点
			SetPixel (hdc, LOWORD (lParam), HIWORD (lParam), 0) ;
			ReleaseDC (hwnd, hdc) ;
		}
		return 0 ;
		
	case WM_LBUTTONUP:
		InvalidateRect (hwnd, NULL, FALSE) ;
		return 0 ;
		
	case WM_PAINT:
		hdc = BeginPaint (hwnd, &ps) ;
		//画图时光标为等待状态
		SetCursor (LoadCursor (NULL, IDC_WAIT)) ;
		ShowCursor (TRUE) ;
		
		for (i = 0 ; i < iCount - 1 ; i++)
			for (j = i + 1 ; j < iCount ; j++)
			{
				MoveToEx (hdc, pt[i].x, pt[i].y, NULL) ;
				LineTo   (hdc, pt[j].x, pt[j].y) ;
			}
			
		ShowCursor (FALSE) ;
		SetCursor (LoadCursor (NULL, IDC_ARROW)) ;
			
		EndPaint (hwnd, &ps) ;
		return 0 ;
			
	case WM_DESTROY:
		PostQuitMessage (0) ;
		return 0 ;
	}
	return DefWindowProc (hwnd, message, wParam, lParam) ;
}


程序比较简单,就不多说了。

那什么是非显示区域的鼠标消息呢?如果鼠标在窗口的显示区域之外但还在窗口内,Windows就给窗口消息处理程序发送一条“非显示区域”鼠标消息。窗口非显示区域包括标题列、菜单和窗口滚动条。

这些消息通常我们是不用管的,将这些消息传给DefWindowProc,从而使Windows执行系统功能。

非显示区域鼠标消息几乎完全与显示区域鼠标消息相对应。消息中含有字母“NC”以表示是非显示区域消息。如果鼠标在窗口的非显示区域中移动,那么窗口消息处理程序会接收到WM_NCMOUSEMOVE消息。鼠标按键产生如表所示的消息:

按下

释放

按下(双击)

WM_NCLBUTTONDOWN

WM_NCLBUTTONUP

WM_NCLBUTTONDBLCLK

WM_NCMBUTTONDOWN

WM_NCMBUTTONUP

WM_NCMBUTTONDBLCLK

WM_NCRBUTTONDOWN

WM_NCRBUTTONUP

WM_NCRBUTTONDBLCLK

但是这些消息参数的意义却不同:

wParam参数指明移动或者按鼠标按键的非显示区域。

lParam参数的低位word为x坐标,高位word为y坐标,但是,它们是屏幕坐标。

最后一个消息是WM_NCHITTEST,它代表“非显示区域命中测试”,Windows应用程序通常把这个消息传送给DefWindowProc,系统会自动的判断你拖动的是标题栏还是边框而做出相应。

你可能感兴趣的:(windows程序设计(14):鼠标消息详解)