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

前面几节讨论了鼠标点击和鼠标移动。以下是一些可以用鼠标执行的其他操作。
拖动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);

鼠标跟踪事件:悬停和离开
其他两个鼠标消息在默认情况下是禁用的,但对于某些应用程序可能有用:

要启用这些消息,请调用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

猜你喜欢

转载自blog.csdn.net/qq_37422196/article/details/79283842