【问题标题】:How to check if scrollbar of an edit control is at the bottom?如何检查编辑控件的滚动条是否在底部?
【发布时间】:2017-04-24 08:47:57
【问题描述】:

编辑:

感谢@immibis,我现在可以使用WM_VSCROLL成功滚动到控件的底部,但我仍然想知道如何检查滚动条是否在底部。

我有一个只读的编辑控件:

HWND hMsgDisplay = CreateWindowEx(WS_EX_CLIENTEDGE, "EDIT", NULL, WS_CHILD | WS_VISIBLE | ES_MULTILINE | ES_READONLY | WS_VSCROLL, 10, 10, 664, 200, hWnd, (HMENU)IDC_MESSAGE_DISPLAY_EDIT, hInst, NULL);

我想滚动到它的底部。我一直在尝试这个:

SCROLLINFO sb;
ZeroMemory(&sb, sizeof(sb));
sb.cbSize = sizeof(SCROLLBARINFO);
sb.fMask = SIF_ALL;
GetScrollInfo(hMsgDisplay, SB_VERT, &sb);
while (abs(sb.nMax - sb.nPos) > 1) {
    SendMessage(hMsgDisplay, EM_SCROLL, SB_LINEDOWN, NULL);
    GetScrollInfo(hMsgDisplay, SB_VERT, &sb);
}

当编辑控件中只有一两行文本时它运行良好,但之后程序进入无限循环并卡住。我调试了它,发现即使滚动条是灰色的(它在那里但不能滚动),sb.nMax 仍然给我一个非零数字,无论我发送多少次EM_SCROLL 消息, sb.nPos 仍然为0。如何检测到滚动条已经滚动到底部?

【问题讨论】:

  • MSDN 说发送 EM_SCROLL 等同于发送 WM_VSCROLL,而 WM_VSCROLL 有一个 SB_BOTTOM 选项。您是否尝试过发送一次以立即滚动到底部?
  • 或者,使用SetScrollPos()SetScrollInfo()(因为您已经知道GetScrollInfo() 的最大位置)。
  • 感谢@immibis 的建议!我刚试了一下,它奏效了。很抱歉在发布这个问题之前没有先查看它......但即使这个问题已经解决了,我仍然想知道你如何检查滚动条是否在底部。
  • nPage 告诉你页面有多大;如果nMax 小于页面大小,则它根本无法滚动。

标签: c++ winapi scrollbar


【解决方案1】:

检查底部位置使用此代码

BOOL IsBotomPos(HWND hwnd)
{
    SCROLLINFO si = {sizeof(si), SIF_ALL};

    if (GetScrollInfo(hwnd, SB_VERT, &si))
    {
        return si.nPos + si.nPage == (UINT)si.nMax + 1;
    }

    return -1;
}

所以条件是si.nPos + si.nPage == (UINT)si.nMax + 1;

这也是返回true 用于空编辑或滚动尚未激活(在本例中为nPos == 0nPage == nMax + 1

滚动到底部你可以简单地调用

SendMessage(hwnd, EM_SCROLL, SB_BOTTOM, 0);

尽管使用 SB_BOTTOMEM_SCROLL 未记录,但它在我的测试中有效

如果你想要平滑滚动 - 你可以使用下一个代码:

void DoSmoothScroll(HWND hwnd, BOOL byPage)
{
    SCROLLINFO si = {sizeof(si), SIF_ALL};

    if (GetScrollInfo(hwnd, SB_VERT, &si))
    {
        int n = si.nMax + 1 - si.nPage - si.nPos;

        if (0 < n)
        {
            if (byPage && si.nPage)
            {
                n = (n + si.nPage - 1) / si.nPage;
                LONG r = MAKELONG(si.nPage - 1, TRUE);
                do 
                {
                    if (SendMessage(hwnd, EM_SCROLL, SB_PAGEDOWN, 0) != r)
                    {
                        break;
                    }
                } while (--n);
            }
            else
            {
                do 
                {
                    if (SendMessage(hwnd, EM_SCROLL, SB_LINEDOWN, 0) != MAKELONG(1, TRUE))
                    {
                        break;
                    }
                } while (--n);
            }
        }
    }
}

您也可以组合 - 首先尝试使用“未记录”SB_BOTTOM 快速滚动,然后检查我们是否真的滚动,如果没有 - 尝试平滑滚动

void ScrollEx(HWND hwnd)
{
    SendMessage(hwnd, EM_SCROLL, SB_BOTTOM, 0);
    DoSmoothScroll(hwnd, TRUE);
}

真的在功能DoSmoothScroll

int n = si.nMax + 1 - si.nPage - si.nPos;

如果SB_BOTTOM 工作并且我们直接退出,则必须为 0,无需额外滚动

【讨论】:

  • @Tyler - 我扩展了 DoSmoothScroll 的代码 - 添加选项选择 - 按页或按行滚动
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-01-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多