如何检测一个 RichTextBox 的滚动条是否在结尾位置(vb.net)

3

我的问题是:如何检测滚动条是否在richtextbox的末尾?编辑:当我说到末尾时,我指的是完全滚动到底部,而不是其他任何地方。

4个回答

2

请查看GetScrollRangeGetScrollPos API...

Private Const SBS_HORZ = 0
Private Const SBS_VERT = 1

<DllImport("user32.dll")> _
Public Function GetScrollRange(ByVal hWnd As IntPtr, ByVal nBar As Integer, _
                               ByRef lpMinPos As Integer, _
                               ByRef lpMaxPos As Integer) As Boolean
End Function

<DllImport("user32.dll")> _
Public Function GetScrollPos(ByVal hWnd As Integer, _
                             ByVal nBar As Integer) As Integer
End Function

// ...

Dim scrollMin as Integer = 0
Dim scrollMax as Integer = 0

If(GetScrollRange(rtb.Handle, SBS_VERT, scrollMin, scrollMax) Then
   Dim pos as Integer = GetScrollPos(rtb.Handle, SBS_VERT)

   // Detect if they're at the bottom
EndIf

注意:

要确定滚动条是否可见,请调用GetWindowLong并检查WS_VSCROLL

要确定滑块可以达到的最大值,请调用GetScrollInfo;我认为最大值是

scrollMax - largeChange + 1

好的,运行得很好,但还有两件事:我如何知道滚动条是否可见,以及如何获取滚动条的最后可能位置? - fbernier
我能够调用getScrollInfo函数,但我不知道如何构建一个能够返回最后位置的函数。你能帮我吗? - fbernier

2
我使用这段代码来正确获取当前和最大位置:
    const int SB_HORZ          = 0x0000;
    const int SB_VERT          = 0x0001;
    const int WM_HSCROLL       = 0x0114;
    const int WM_VSCROLL       = 0x0115;
    const int SB_THUMBPOSITION = 4;

    private enum ScrollInfoMask : uint
    {
        SIF_RANGE           = 0x1,
        SIF_PAGE            = 0x2,
        SIF_POS             = 0x4,
        SIF_DISABLENOSCROLL = 0x8,
        SIF_TRACKPOS        = 0x10,
        SIF_ALL             = (SIF_RANGE | SIF_PAGE | SIF_POS | SIF_TRACKPOS)
    }

    [StructLayout(LayoutKind.Sequential)]
    struct SCROLLINFO
    {
        public uint cbSize;
        public uint fMask;
        public int  nMin;
        public int  nMax;
        public uint nPage;
        public int  nPos;
        public int  nTrackPos;
    }

    public int HScrollPosition
    {
        get
        {
            return GetScrollPos(Handle, SB_HORZ);
        }
        set
        {
            SetScrollPos((IntPtr)Handle, SB_HORZ, value, true);
            PostMessageA((IntPtr)Handle, WM_HSCROLL, SB_THUMBPOSITION + 0x10000 * value, 0);
        }
    }

    public int VScrollPosition
    {
        get
        {
            return GetScrollPos(Handle, SB_VERT);
        }
        set
        {
            SetScrollPos((IntPtr)Handle, SB_VERT, value, true);
            PostMessageA((IntPtr)Handle, WM_VSCROLL, SB_THUMBPOSITION + 0x10000 * value, 0);
        }
    }

    public int HScrollPositionMax
    {
        get
        {
            SCROLLINFO scrollInfo = new SCROLLINFO();
            scrollInfo.fMask = (uint)ScrollInfoMask.SIF_ALL;
            scrollInfo.cbSize = (uint)Marshal.SizeOf(scrollInfo);
            GetScrollInfo(Handle, SB_HORZ, ref scrollInfo);

            return scrollInfo.nMax - (int)scrollInfo.nPage;
        }
    }

    public int VScrollPositionMax
    {
        get
        {
            SCROLLINFO scrollInfo = new SCROLLINFO();
            scrollInfo.fMask = (uint)ScrollInfoMask.SIF_ALL;
            scrollInfo.cbSize = (uint)Marshal.SizeOf(scrollInfo);
            GetScrollInfo(Handle, SB_VERT, ref scrollInfo);

            return scrollInfo.nMax - (int)scrollInfo.nPage;
        }
    }

获取“正确”的最大值很繁琐。您需要从GetScrollRange返回的最大值中减去nPage(大改变)值,然后才能正确地将其与HScrollPosition属性进行比较,例如:

if (_rtb.VScrollPosition == _rtb.VScrollPositionMax)
{
    Debug.WriteLine("Scroll is at the bottom most edge");
}

我注意到当RichTextBox的“显示”区域高度不是字体高度的倍数时,有时滚动位置(例如nPos)与最大值(例如nMax-nPage)并不完全相等,因为在最后一行文本下面有一行“部分行”文本,但滚动位置被量化为最近的一行,使nMax比预期高一些。我想也可以从nMax中减去一行文本的高度减一--这样,一个足够接近的滚动位置就算作是“最大”。可能会尝试一下;之后再报告。 - bernz

1
        if (richTextBox1.Size.Width - richTextBox1.ClientSize.Width > 10) 

抱歉,您需要自己将其转换为VB.NET。这应该不难 :)


0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接