其他滑鼠作業
前幾節已討論滑鼠點擊和滑鼠移動。 以下是一些可以使用滑鼠執行的其他作業。
拖曳 UI 元素
如果您的 UI 支援拖曳 UI 元素,您應該在滑鼠向下訊息處理常式中呼叫其他函式: DragDetect。 如果使用者起始應該解譯為拖曳的滑鼠手勢, DragDetect 函式會傳回 TRUE 。 下列程式碼示範如何使用此函式。
case WM_LBUTTONDOWN:
{
POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
if (DragDetect(m_hwnd, pt))
{
// Start dragging.
}
}
return 0;
以下是概念:當程式支援拖放時,您不希望每個滑鼠按一下都解譯為拖曳。 否則,當使用者只是想要按一下它 (時,使用者可能會不小心拖曳某個專案,以選取它) 。 但是,如果滑鼠特別敏感,按一下滑鼠時可能很難讓滑鼠保持完美。 因此,Windows 會定義數個圖元的拖曳閾值。 當使用者按下滑鼠按鍵時,除非滑鼠超過此閾值,否則不會被視為拖曳。 DragDetect函式會測試是否已達到此臨界值。 如果函式傳回 TRUE,您可以將滑鼠按一下解譯為拖曳。 否則,請勿。
注意
如果 DragDetect 傳回 FALSE,當使用者放開滑鼠按鍵時,Windows 會隱藏 WM_LBUTTONUP 訊息。 因此,除非您的程式目前處於支援拖曳的模式,否則請勿呼叫 DragDetect 。 (例如,如果已選取可拖曳的 UI 元素。) 在本課程模組結束時,我們將會看到使用 DragDetect 函式的較長程式碼範例。
限制游標
有時候,您可能想要將游標限制在工作區或工作區的一部分。 ClipCursor函式會將游標的移動限制為指定的矩形。 此矩形是以螢幕座標提供,而不是用戶端座標,因此點 (0,0) 表示螢幕左上角。 若要將用戶端座標轉譯成螢幕座標,請呼叫 函式 ClientToScreen。
下列程式碼會將游標限制在視窗的工作區。
// Get the window client area.
RECT rc;
GetClientRect(m_hwnd, &rc);
// Convert the client area to screen coordinates.
POINT pt = { rc.left, rc.top };
POINT pt2 = { rc.right, rc.bottom };
ClientToScreen(m_hwnd, &pt);
ClientToScreen(m_hwnd, &pt2);
SetRect(&rc, pt.x, pt.y, pt2.x, pt2.y);
// Confine the cursor.
ClipCursor(&rc);
ClipCursor 會採用 RECT 結構,但 ClientToScreen 會採用 POINT 結構。 矩形是由其左上方和右下角點所定義。 您可以將游標限制在任何矩形區域,包括視窗外的區域,但將游標限制在工作區是使用函式的一般方式。 將游標限制在視窗外的整個區域是不尋常的,而且使用者可能會將其視為 Bug。
若要移除限制,請使用Null值呼叫ClipCursor。
ClipCursor(NULL);
滑鼠追蹤事件:暫留和離開
預設會停用其他兩個滑鼠訊息,但對某些應用程式可能很有用:
- WM_MOUSEHOVER:游標已停留在工作區上一段固定的時間。
- WM_MOUSELEAVE:游標已離開工作區。
若要啟用這些訊息,請呼叫 TrackMouseEvent 函式。
TRACKMOUSEEVENT tme;
tme.cbSize = sizeof(tme);
tme.hwndTrack = hwnd;
tme.dwFlags = TME_HOVER | TME_LEAVE;
tme.dwHoverTime = HOVER_DEFAULT;
TrackMouseEvent(&tme);
TRACKMOUSEEVENT結構包含函式的參數。 結構的 dwFlags 成員包含位旗標,指定您感興趣的追蹤訊息。 您可以選擇同時取得 WM_MOUSEHOVER 和 WM_MOUSELEAVE,如下所示,或只取得兩者之一。 dwHoverTime成員會指定滑鼠在系統產生暫留訊息之前需要暫留的時間長度。 這個值是以毫秒為單位來指定。 常數 HOVER_DEFAULT 表示使用系統預設值。
取得您要求的其中一個訊息之後, TrackMouseEvent 函式就會重設。 您必須再次呼叫它,才能取得另一個追蹤訊息。 不過,您應該等到下一個滑鼠移動訊息,再再次呼叫 TrackMouseEvent 。 否則,您的視窗可能會被追蹤訊息填滿。 例如,如果滑鼠暫留,系統會在滑鼠靜止時繼續產生 WM_MOUSEHOVER 訊息的資料流程。 您實際上不會想要另一個 WM_MOUSEHOVER 訊息,直到滑鼠移至另一個位置並再次暫留為止。
以下是可用來管理滑鼠追蹤事件的小型協助程式類別。
class MouseTrackEvents
{
bool m_bMouseTracking;
public:
MouseTrackEvents() : m_bMouseTracking(false)
{
}
void OnMouseMove(HWND hwnd)
{
if (!m_bMouseTracking)
{
// Enable mouse tracking.
TRACKMOUSEEVENT tme;
tme.cbSize = sizeof(tme);
tme.hwndTrack = hwnd;
tme.dwFlags = TME_HOVER | TME_LEAVE;
tme.dwHoverTime = HOVER_DEFAULT;
TrackMouseEvent(&tme);
m_bMouseTracking = true;
}
}
void Reset(HWND hwnd)
{
m_bMouseTracking = false;
}
};
下一個範例示範如何在視窗程式中使用此類別。
LRESULT MainWindow::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_MOUSEMOVE:
mouseTrack.OnMouseMove(m_hwnd); // Start tracking.
// TODO: Handle the mouse-move message.
return 0;
case WM_MOUSELEAVE:
// TODO: Handle the mouse-leave message.
mouseTrack.Reset(m_hwnd);
return 0;
case WM_MOUSEHOVER:
// TODO: Handle the mouse-hover message.
mouseTrack.Reset(m_hwnd);
return 0;
}
return DefWindowProc(m_hwnd, uMsg, wParam, lParam);
}
滑鼠追蹤事件需要系統的額外處理,因此如果您不需要它們,請將其停用。
為了完整起見,以下是查詢系統的預設暫留逾時函式。
UINT GetMouseHoverTime()
{
UINT msec;
if (SystemParametersInfo(SPI_GETMOUSEHOVERTIME, 0, &msec, 0))
{
return msec;
}
else
{
return 0;
}
}
滑鼠滾輪
下列函式會檢查滑鼠滾輪是否存在。
BOOL IsMouseWheelPresent()
{
return (GetSystemMetrics(SM_MOUSEWHEELPRESENT) != 0);
}
如果使用者旋轉滑鼠滾輪,具有焦點的視窗會收到 WM_MOUSEWHEEL 訊息。 此訊息的 wParam 參數包含一個整數值,稱為 差異 ,可測量滾輪旋轉的距離。 差異會使用任意單位,其中 120 個單位定義為執行一個「動作」所需的旋轉。當然,動作的定義取決於您的程式。 例如,如果使用滑鼠滾輪來捲動文字,則每 120 個旋轉單位都會捲動一行文字。
差異的正負號表示旋轉方向:
- 正數:向前旋轉,離開使用者。
- 負數:向後旋轉,向使用者旋轉。
差異的值會放在 wParam 中,以及一些額外的旗標。 使用 GET_WHEEL_DELTA_WPARAM 宏來取得差異的值。
int delta = GET_WHEEL_DELTA_WPARAM(wParam);
如果滑鼠滾輪具有高解析度,差異的絕對值可能小於 120。 在此情況下,如果動作的增量較小,您可以這麼做。 例如,文字可能會以小於一行的遞增捲動。 否則,請累積總差異,直到滾輪旋轉足以執行動作為止。 將未使用的差異儲存在變數中,當 120 單位累積 (正數或負數) 時,請執行動作。
下一個