您的位置:首页 > 其它

Windows桌面应用程序(1-2-5-4th) 其他鼠标操作

2018-02-07 20:08 337 查看
前面几节讨论了鼠标点击和鼠标移动。以下是一些可以用鼠标执行的其他操作。

拖动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结构。矩形由左上角和右下角定义。您可以将光标限制在任何矩形区域,包括窗口外的区域,但将光标限制在客户区域是使用该功能的典型方法。将光标限制在完全位于窗口外的区域将是不寻常的,用户可能会将其视为一个错误。

要删除该限制,请使用值为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_MOUSEHOVERWM_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消息。该消息的lParam参数包含一个称为delta的整数值,用于测量车轮旋转的距离。三角洲使用任意单位,其中120单位被定义为执行一个“行动”所需的轮换。当然,一个行动的定义取决于你的程序。例如,如果使用鼠标滚轮来滚动文字,则每120个旋转单位将滚动一行文字。

三角洲的符号表示旋转的方向:

正向:向前旋转,远离用户。

负面:向后旋转,朝向用户。

增量的值与一些附加的标志一起被放置在lParam中。使用GET_WHEEL_DELTA_WPARAM宏来获取增量的值。

int delta=GET_WHEEL_DELTA_WPARAM(wParam);


如果鼠标滚轮具有较高的分辨率,则增量的绝对值可能小于120。在这种情况下,如果以较小的增量出现动作是有意义的,则可以这样做。例如,文本可以以小于一行的增量滚动。否则,积累总的三角洲,直到轮旋转足够执行行动。将未使用的增量存储在一个变量中,当120个单位累加(正数或负数)时,执行该操作。

下一个

键盘输入

原文链接:Miscellaneous Mouse Operations
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: