老長時間沒有更新Windows程式設計的內容了,今天看了一段Windows程式設計檔案操作的內容,同時想起滑鼠操作還沒有更新過
文字,這裡先就寫一點關於滑鼠文字吧。
一、滑鼠
(1)
Windows支援單鍵、雙鍵和三鍵滑鼠,還可以使用操縱杆或者光筆類比滑鼠。
1、判斷系統是否存在滑鼠
在使用滑鼠之前必須判斷系統中是否存在滑鼠,可通過函數GetSystemMetrics來判斷滑鼠是否存在。
bMouse=GetSystemMetrics(SM_MOUSEPRESENT);
若安裝了滑鼠,則bMouse將返回TRUE,否則就返回0.
要點:
Windows98中無論是否安裝滑鼠,這個函數都將返回TRUE。
2、判斷滑鼠的鍵數
通過GetSystemMetrics函數還可以確定安裝的滑鼠的鍵鼠,只要將傳遞給函數是參數改為:SM_CMOUSEBUTTONS 即可判斷
系統中滑鼠的鍵;如果沒有安裝滑鼠,那麼函數將返回0;在Windows98中,無論有沒有安裝滑鼠,這個函數都將返回2.
3、判斷滑鼠是否切換過左右手
通過向GetSystemMetrics函數傳遞SM_SWAPBUTTON是否進行了這種切換;
(2) windows預定義
當Windows使用者移動滑鼠時,在螢幕上將有一個“滑鼠游標”的小位元影像,隨著使用者的移動而移動。滑鼠游標上有一個指向螢幕上精確
位置的單象素“熱點”。
Windows支援預定義的滑鼠游標:IDC_ARROW(箭頭游標)、IDC_CROSS(十字游標)、IDC_WAIT(游標);箭頭游標的熱點在
箭頭的頂端,十字游標的熱點在中心。
Windows支援使用者自訂滑鼠游標;在定義視窗類別的時候,我們可以指定預定義的滑鼠游標為視窗預設滑鼠。
通過下面的語句指定視窗預設游標:
wndclass.hCursor=LoadCursor(NULL,IDC_ARROW);
滑鼠操作術語:
單擊:按下並鬆開一個滑鼠鍵
雙擊:快速按下並鬆開滑鼠鍵兩次
拖曳:按住滑鼠鍵並移動滑鼠
滑鼠鍵名:
左鍵:LBUTTON
中鍵:MBUTTON
右鍵:RBUTTON
雙鍵滑鼠只有左鍵與右鍵,單鍵滑鼠只有一個左鍵。
(3)客戶區滑鼠訊息
滑鼠在使用者視窗移動、按鍵視窗都會收到訊息;這一點與鍵盤訊息不一樣:只有擁有輸入焦點的視窗才能接收鍵盤訊息。
Windows一共定義了21種滑鼠訊息,其中10種是客戶去訊息,而有11中是非客戶去訊息,使用者程式經常忽略非客戶區訊息。當滑鼠從視窗移動
時,視窗會接收到WM_MOUSEMOVE訊息;當使用者在視窗客戶去按下滑鼠鍵的時候會接受到如下滑鼠訊息:
只有三鍵滑鼠才會接收到中鍵滑鼠訊息,只有雙鍵、三鍵滑鼠才能接收到右鍵訊息;僅當定義的視窗類別能接收DBLCLK雙擊訊息之後,視窗
才能接收到這些訊息。
對於視窗接收到的滑鼠訊息,lParam參數的值均含有滑鼠的位置:低位字為x座標,高位字為y座標,lParam參數為32位,字定義為16位;
當要處理滑鼠訊息時可以通過:
x=LOWORD(lParam);
y=HIWORD(lParam);
擷取當前滑鼠訊息的熱點座標,x、y的值均是相對於視窗客戶區左上方頂點而言;這與通常使用的座標有點不一樣。
Windows定義wParam參數指示滑鼠鍵及Shift和Ctrl鍵的狀態,在程式中,可以使用WINUSER.H定義的位旗標來測試wParam參數。
MK代表滑鼠訊息,可以利用下面的語句測試按鍵的狀態:
if(wParam&MK_SHIFT)
statement;
如果接收到WM_LBUTTONDOWN訊息的時候,上面的statement語句能執行,則表示按下左鍵的時候同步選取了shift鍵。
Windows不能在滑鼠移動過程中,為熱點經過的每個像素都發送WM_MOUSEMOVE訊息,視窗接收到訊息的速度取決於滑鼠移動的速度
以及視窗過程處理移動訊息的速度;即Windows不能用未處理的WM_MOUSEMOVE訊息來填充訊息佇列,(為了驗證這個特性,可以利用spy
程式來監控滑鼠訊息和視窗處理訊息的情況)
視窗處理滑鼠訊息的過程如下:
非使用中視窗——>按下滑鼠——》視窗變成使用中視窗——》發送滑鼠訊息到視窗過程,
使用中視窗——》按下滑鼠——》發送滑鼠訊息到視窗過程
上述過程是一般的過程,但是這個過程有時候會變成其他樣子,當有模態視窗存在時,這個過程可能變得不一樣,需要
注意。
視窗接收到的訊息也不一定是按下左鍵/按下右鍵為接收到第一個滑鼠訊息;例如我們在第一個視窗按下滑鼠左鍵,而
後將滑鼠移動到第二個視窗釋放;那麼第二個視窗接收到滑鼠訊息將會先是WM_MOUSEMOVE,然後是WM_LBUTTONUP訊息,
因此在處理的時候需要注意。
例外情況:
(4)處理shift和Ctrl鍵與滑鼠組合訊息
前面說過,可以通過wParam參數和位旗標的與運算來查看是否按下了滑鼠和shift/ctrl這樣的組合訊息。
在滑鼠訊息中可以通過下面的語句來確定是否按下了shift和Ctrl鍵
if(wParam & MK_SHIFT)
{
if(wParam & MK_CONTROL)
{滑鼠訊息的同步選取了shift和ctrl鍵}
else
{滑鼠鍵的同步選取shift鍵}
}
else
{
if(wParam & MK_CONTROL)
{滑鼠訊息的同步選取了ctrl鍵}
else
{僅有滑鼠訊息}
}
在使用者程式中可以通過利用滑鼠和鍵盤的組合訊息來類比滑鼠訊息,這樣在單鍵滑鼠的情況下就可以實現右鍵滑鼠訊息的處理。具體
我們就不用執行個體代碼說明了。
Windows使用函數GetKeyState通過虛擬鍵碼VK_LBUTTON、VK_RBUTTON、VK_MBUTTON、VK_SHIFT、VK_CONTROL來返回
滑鼠鍵與shift鍵的狀態。如果GetKeySate返回負值,則說明按下了滑鼠鍵或者shift鍵。因為GetKeyState返回當前正在處理的滑鼠鍵或者shift
鍵的狀態,所以全部狀態訊息都與相應的訊息時同步的。
(5)雙擊滑鼠鍵
雙擊滑鼠鍵是指在短時間內單擊兩次。
雙擊條件: 1、兩次單擊發生時滑鼠游標熱點的距離必須在系統規定的方位之內
2、兩次單擊發生的時間間隔在指定的時間範圍內;可以在系統控制台中改變滑鼠雙擊時間間隔。
如果要使得視窗能接收雙擊滑鼠訊息,那麼視窗的風格必須有CS_DBLCLKS位旗標。如下所示:
wndclass.style=CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
如果沒有設定視窗風格,那麼雙擊時視窗將接收下面一系列的訊息:
如果設定了視窗風格將接收到:
如上所示,這兩個訊息佇列,僅是第三個訊息發生了變化。
如果雙擊中的第一個單擊操作完成某個單擊功能,則處理雙擊訊息很容易,那麼第二次單擊訊息則用來完成第一次單擊以外的事情;
這裡如:
Windows資源管理員的滑鼠的單擊選定,而雙擊開啟; 當然可以在系統中設計指向選定而單擊開啟,不過這不符合大多數人的操
作習慣。
(6)非客戶區滑鼠訊息
如果滑鼠在視窗之內,但是在客戶區之外,那麼視窗將會接收系統發送的非客戶區滑鼠訊息;視窗的非客戶區包括標題列、功能表列和
視窗捲軸,一般情況下,使用者程式不需要處理非視窗滑鼠訊息,而將這些訊息由DefWindowProc函數處理。
Windows用“NC” 表示非客戶區訊息,如果滑鼠在視窗的非客戶區中移動,那麼視窗過程接收到WM_NCMOUSEMOVE訊息。非客
戶區訊息如下所示:
因為非客戶區有幾個地區,因此我們在處理非客戶區訊息的時候,還需要分辨是在標題列、功能表列還是捲軸的滑鼠訊息。
為了實現分辨地區:可以藉助wParam、lParam參數來分辨。客戶區的滑鼠訊息和非客戶區滑鼠訊息的wParam、lParam參數是不一樣的,wParam
參數指明發送滑鼠訊息的非客戶區位置。當有非客戶區滑鼠訊息時,wParam設定為一HT開始的宏標識符(HT表示點擊測試)
當有非客戶區滑鼠訊息時,lParam參數返回滑鼠訊息發生時熱點的座標,但是此時的座標為螢幕座標,而不是客戶區座標。螢幕座標以螢幕的左上方頂
點為座標原點(0,0);當滑鼠往右移動時x增加,滑鼠往下移動時y增加。
可以利用Windows函數在螢幕座標和客戶區座標進行轉換:
ScreenToClient(hwnd,&pt);
ClientToScreen(hwnd,&pt);
(8)點擊測試訊息
在Windows中設定了點擊測試訊息WM_NCHITTEST,此訊息優先於所有其他的客戶區和非客戶區滑鼠訊息,lParam參數含有滑鼠位置的
x和y螢幕座標,wParam參數沒有用。
Windows應用程式通常把這個訊息傳遞給DefWindowProc,然後Windows用WM_NCHITTEST訊息產生基於滑鼠位置的其他滑鼠訊息;
對於非客戶區滑鼠訊息,當處理WM_NCHITTEST訊息時,從DefWindowProc返回的範圍將成為滑鼠訊息中的wParam參數,這個值可以是任
意非客戶區滑鼠訊息的wParam值再加上以下內容:
HTCLIENT: 客戶區
HTNOWHERE:不在視窗中
HTTRANSPARENT:視窗由另一個視窗覆蓋
HTERROR:使DefWindowProc產生蜂鳴聲
如果DefWindowProc在處理WM_NCHITTEST訊息後返回HTCLIENT,那麼Windows將把螢幕座標轉換為客戶區座標,併產生客戶區滑鼠訊息。
因為WM_NCHITTEST訊息在所有的滑鼠訊息前處理,因此我們可以利用這一點來禁用所有的滑鼠訊息:
在視窗過程函數中我們可以這樣做:
case WM_NCHITTEST:
return (LRESULT)WM_NCHITTEST;
這樣就可以禁用所有的視窗滑鼠訊息。
利用點擊測試訊息,Windows程式設計了一個訊息產生訊息的機制,我們可以利用視窗的系統功能表的滑鼠雙擊來分析這個過程:
滑鼠雙擊視窗系統功能表——》WM_NCHITTEST訊息——》DefWindowProc處理WM_NCHITTEST訊息,後返回——》DefWindowProc將
WM_NCLBUTTONDBLCLK訊息放到訊息佇列,並把wParam設定為HTSYSMENU——》通常使用者程式不會處理WM_NCLBUTTONDBLCLK
訊息,而把訊息交給DefwindowProc函數處理——》DefwindowProc接收到wParam=HTSYSMENU的WM_NCLBUTTONDBLCLK
訊息後;將WM_SYSCOMMAND訊息放入訊息佇列中,並設定wParam=SC_CLOSE參數——》視窗過程把這個WM_SYSCOMMAND訊息
傳給DefWindowProc函數處理——》DefwindowProc通過給視窗發送WM_CLOSE訊息。
如果使用者程式不處理WM_CLOSE訊息,那麼DefWindowProc將處理這個訊息;DefwindowProc函數接收到WM_CLOSE訊息後,將調用
DestroyWindow函數來處理WM_CLOSE,除了其他處理,DestroyWindow還給視窗過程發送WM_DESTROY訊息,視窗過程通常用下列
代碼來處理WM_DESTROY訊息:
case WM_DESTROY:
PostQiutMessage(0);
retrun 0;
PostQiutMessage使Windows把WM_QUIT訊息放入訊息佇列中,這個訊息永遠不會經由視窗過程處理,因為WM_DESTROY訊息將
是GetMessage函數返回0,終止訊息迴圈,從而退出程式。
(9)捕獲滑鼠
有時候,可能在滑鼠離開視窗後還想獲得滑鼠訊息,這時候我們就需要捕獲滑鼠。
例如:
在畫圖程式中,需要畫矩形,我們按下鼠表左鍵,然後拖曳滑鼠到適合大小,接下來釋放滑鼠,就可以繪出矩形;但是假如在拖曳的過程
中滑鼠離開了視窗的客戶區,那麼原來的視窗就不能接受滑鼠釋放的訊息,這時沒有辦法確定矩形的大小,就不知道如何繪製矩形了,
為了處理上面的問題,可以通過滑鼠捕獲功能來實現。
Windows提供了函數捕獲滑鼠,如下所示:
SetCapture(hwnd);
在調用這個函數後,Windows會將以後的所有滑鼠訊息發送給視窗控制代碼為hwnd的視窗過程,並且滑鼠訊息都將是客戶區訊息,即使滑鼠在非客戶區;
lParam參數將指示滑鼠在座標中的位置。不過LOWORD(lParam)和HIORD(lParam)返回的值可能為正也為負,這與滑鼠發送訊息的位置有關。
當要釋放滑鼠時,調用
ReleaseCapture(hwnd);
就可以使訊息恢複到捕獲前的狀態。
我們知道在視窗1按下滑鼠鍵,並且視窗1滑鼠被捕獲,然後移動到視窗2,接下來釋放滑鼠鍵,那麼視窗1將不能接收到滑鼠釋放訊息,而視窗2將接收
滑鼠訊息,這時將不是捕獲滑鼠的那個視窗接收滑鼠訊息,而是由游標下面的視窗來接收滑鼠訊息;
為了防止捕獲產生的異常狀態,只有當滑鼠鍵在視窗的客戶區中被按下時才捕獲滑鼠,當鍵被釋放時才釋放滑鼠捕獲。