如何检测用户拖动滚动条旋钮

时间:2017-07-06 14:27:24

标签: winapi scrollbar

我有(旧的)代码用SetScrollRange()更新背景中的滚动条位置和最小值 - 最大值,但是当用户拖动滚动条旋钮时,此代码不应运行在视觉上跳回到原始位置,然后在拖动或释放鼠标时跳回到用户选择的位置。

是否有一些简单的方法来检测拖动是否正在进行?

2 个答案:

答案 0 :(得分:4)

当用户拖动滚动条的拇指时,滚动条的所有者窗口会收到WM_VSCROLL(垂直)或WM_HSCROLL(水平)消息(取决于滚动条的方向),其中wParam值的单词设置为SB_THUMBTRACK,hi-word设置为新位置。

当用户松开拇指时,所有者窗口会收到两条最终WM_(V|H)SCROLL条消息:

  • 第一条消息的wParam值设置为SB_THUMBPOSITION并且hi-word设置为新位置。
  • 第二条消息的wParam的单词设置为TB_ENDTRACK

您可以继承拥有滚动条的UI控件来拦截这些消息。当您看到任何WM_(V|H)SCROLL条消息时,在看到TB_ENDTRACK通知之前,请勿对滚动条进行更新。

答案 1 :(得分:1)

我可以想到两种方法来做到这一点。简单(和hacky)的方法是调用GetCapture()。它将返回捕获鼠标的当前窗口的HWND值,如果未捕获鼠标,则返回NULL。这只是意味着用户已在滚动条控件中按下鼠标按钮而不释放鼠标按钮。

更好的方法是将控件子类化。下面是一些示例代码,说明如何拖动滚动条的“拇指”来设置标记:

// Somewhere in your code, subclass the scrollbar
WNDPROC originalScrollBarWndProc = (WNDPROC) SetWindowLongPtr(scrollBarHwnd, GWLP_WNDPROC, (LONG_PTR) myScrollBarWndProc);

LRESULT CALLBACK myScrollBarWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch(message)
    {
        case WM_LBUTTONDOWN:
        {
            // Get Y position of the mouse
            uint16_t mouseYPos = HIWORD(lParam); // Change this to LOWORD for horizontal scrollbars

            // Get the top and bottom coordinates of the scrollbar thumb
            SCROLLBARINFO sbi = {0};
            sbi.cbSize = sizeof(SCROLLBARINFO);

            if(GetScrollBarInfo(hwnd, OBJID_CLIENT, &sbi) == 0)
            {
                // Failed to get scroll bar info, handle however you want
                break;
            }

            // Check if the WM_LBUTTONDOWN event happened over the scrollbar thumb
            if(mouseYPos >= sbi.xyThumbTop && mouseYPos <= sbi.xyThumbBottom)
            {
                // Set a flag to indicate that the thumb is being "dragged"
                // I chose to do this using SetWindowLongPtr; Do it however you like.
                SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR) 1);
            }
        }
        break;

        case WM_LBUTTONUP:
        {
            // Mouse button was released, clear the flag
            SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR) 0);
        }
        break;

        /* ... other cases here, if needed ... */
    }

    return CallWindowProc(originalScrollBarWndProc, hwnd, message, wParam, lParam);
}

使用上面的代码,你所要做的就是调用GetWindowLongPtr(scrollBarHwnd,GWLP_USERDATA)并检查值是0还是1以查看它是否被拖动。

我不是肯定的,这是解决问题的最佳方法,但我相信它至少是一个很好用的方法。