防止 RichTextBox 自动滚动

发布于 2024-07-15 07:45:17 字数 180 浏览 9 评论 0原文

我有一个使用 RichTextBox 控件实现的只读数据记录窗口。 我希望能够禁用用户单击控件时发生的自动滚动,以便用户可以选择特定日志进行复制/粘贴操作或其他操作。 但是,一旦用户单击 RichTextBox,它就会自动滚动到底部,这使得这变得很困难。

有人知道一种方法来覆盖这种行为吗?

谢谢!

I have a readonly data logging window that I implemented using the RichTextBox control. I'd like to be able to disable the autoscrolling that happens when the user clicks in the control so that the user can select a specific log for copy/paste operations or whatever. However, as soon as the user clicks in the RichTextBox, it automatically scrolls to the bottom, making this difficult.

Anyone know a way to override this behavior?

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

长不大的小祸害 2024-07-22 07:45:17

如果未隐藏所选内容,RichTextBox 控件会自动滚动到当前所选内容。 RichTextBox.AppendText() 除了附加文本之外,还修改当前选择,因此间接触发“自动滚动”行为。 请注意,如果 RichTextBox.HideSelection 设置为 true,则当控件未处于焦点时,所选内容将被隐藏; 这解释了您所描述的行为,其中仅当用户单击控件时才会发生自动滚动。 (从而给予它焦点)
为了防止这种情况,您需要在附加文本时执行以下操作:

  1. 备份初始选择
  2. 取消控件
  3. 焦点 隐藏选择(通过 Windows 消息)
  4. AppendText
  5. 恢复初始选择
  6. 取消隐藏选择
  7. 重新聚焦控件

您可能还想检查选择是否已经存在在文本末尾,并允许自动滚动行为(如果是)- 这本质上模拟了 Visual Studio 输出窗口的行为。 例如:

    [System.Runtime.InteropServices.DllImport("user32.dll")]
    static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, Int32 wParam, Int32 lParam);
    const int WM_USER = 0x400;
    const int EM_HIDESELECTION = WM_USER + 63;

    void OnAppend(string text)
    {
        bool focused = richTextBox1.Focused;
        //backup initial selection
        int selection = richTextBox1.SelectionStart;
        int length = richTextBox1.SelectionLength;
        //allow autoscroll if selection is at end of text
        bool autoscroll = (selection==richTextBox1.Text.Length);

        if (!autoscroll)
        {
            //shift focus from RichTextBox to some other control
            if (focused) textBox1.Focus();
            //hide selection
            SendMessage(richTextBox1.Handle, EM_HIDESELECTION, 1, 0);
        }

        richTextBox1.AppendText(text);

        if (!autoscroll)
        {
            //restore initial selection
            richTextBox1.SelectionStart = selection;
            richTextBox1.SelectionLength = length;
            //unhide selection
            SendMessage(richTextBox1.Handle, EM_HIDESELECTION, 0, 0);
            //restore focus to RichTextBox
            if(focused) richTextBox1.Focus();
        }
    }

The RichTextBox control automatically scrolls to the current selection, if the selection is not hidden. RichTextBox.AppendText(), in addition to appending text, also modifies the current selection, and so indirectly triggers the "autoscrolling" behaviour. Note that if RichTextBox.HideSelection is set to true, then the selection would be hidden when the control is not in focus; this explains the behaviour you described, where autoscrolling occurs only when the user clicks in the control. (thereby giving it focus)
To prevent this, you need to do the following when appending text:

  1. Backup the initial selection
  2. Unfocus the control
  3. Hide selection (through a Windows message)
  4. AppendText
  5. Restore the initial selection
  6. Unhide selection
  7. Refocus the control

You may also want to check whether the selection is already at the end of the text, and allow the autoscrolling behaviour if it is - this essentially emulates the behaviour of Visual Studio's Output window. For example:

    [System.Runtime.InteropServices.DllImport("user32.dll")]
    static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, Int32 wParam, Int32 lParam);
    const int WM_USER = 0x400;
    const int EM_HIDESELECTION = WM_USER + 63;

    void OnAppend(string text)
    {
        bool focused = richTextBox1.Focused;
        //backup initial selection
        int selection = richTextBox1.SelectionStart;
        int length = richTextBox1.SelectionLength;
        //allow autoscroll if selection is at end of text
        bool autoscroll = (selection==richTextBox1.Text.Length);

        if (!autoscroll)
        {
            //shift focus from RichTextBox to some other control
            if (focused) textBox1.Focus();
            //hide selection
            SendMessage(richTextBox1.Handle, EM_HIDESELECTION, 1, 0);
        }

        richTextBox1.AppendText(text);

        if (!autoscroll)
        {
            //restore initial selection
            richTextBox1.SelectionStart = selection;
            richTextBox1.SelectionLength = length;
            //unhide selection
            SendMessage(richTextBox1.Handle, EM_HIDESELECTION, 0, 0);
            //restore focus to RichTextBox
            if(focused) richTextBox1.Focus();
        }
    }
凑诗 2024-07-22 07:45:17

您可能会看看做这样的事情:

[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern IntPtr LockWindowUpdate(IntPtr Handle);

然后在您附加日志数据的方法中(我在这里做了一些假设)您可能会做这样的事情:

LockWindowUpdate(this.Handle);
int pos = richTextBox1.SelectionStart;
int len = richTextBox1.SelectionLength;
richTextBox1.AppendText(yourText);
richTextBox1.SelectionStart = pos;
richTextBox1.SelectionLength = len;
LockWindowUpdate(IntPtr.Zero);

我做了一个带有计时器的小测试应用程序,该计时器在richtextbox 它阻止了它的滚动,这样我就可以进行文本选择。 它存在一些位置问题并且并不完美,但也许它会帮助您找到自己的解决方案。

一切顺利!

You might take a look at doing something like this:

[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern IntPtr LockWindowUpdate(IntPtr Handle);

then in your method that appends log data (I'm making some assumptions here) you might do something like this:

LockWindowUpdate(this.Handle);
int pos = richTextBox1.SelectionStart;
int len = richTextBox1.SelectionLength;
richTextBox1.AppendText(yourText);
richTextBox1.SelectionStart = pos;
richTextBox1.SelectionLength = len;
LockWindowUpdate(IntPtr.Zero);

I did a little test app with a timer that did the append on the richtextbox and it stopped it from scrolling so I could do the text selection. It has some positional issues and isn't perfect, but perhaps it'll help move you toward a solution of your own.

All the best!

我不吻晚风 2024-07-22 07:45:17

SytS 的解决方案有一个问题,当“附加”某些文本时,滚动条会移动,使得选择内容转到面板顶部。
解决方案是保存/恢复滚动位置:

    [System.Runtime.InteropServices.DllImport("User32.dll")]
    extern static int GetScrollPos(IntPtr hWnd, int nBar);

    [System.Runtime.InteropServices.DllImport("user32.dll")]
    static extern int SetScrollPos(IntPtr hWnd, int nBar, int nPos, bool bRedraw);

这个解决方案对我来说更完整。

SytS's solution has an issue, when some text is "appended", the scroll bar moves such that the selection go to the top of the panel.
A solution is to save/restore the scroll position with :

    [System.Runtime.InteropServices.DllImport("User32.dll")]
    extern static int GetScrollPos(IntPtr hWnd, int nBar);

    [System.Runtime.InteropServices.DllImport("user32.dll")]
    static extern int SetScrollPos(IntPtr hWnd, int nBar, int nPos, bool bRedraw);

This solution is more complete for me.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文