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 <windows.h>
#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,系統會自動的判斷你拖動的是標題欄還是邊框而做出相應。