簡體   English   中英

如何自動滾動到多行文本框的底部?

[英]How do I automatically scroll to the bottom of a multiline text box?

我有一個文本框,其 .Multiline 屬性設置為 true。 我會定期向其中添加新的文本行。 我希望文本框在添加新行時自動滾動到最底部的條目(最新的條目)。 我該如何做到這一點?

每隔一段時間,我就會向其中添加新的文本行。 我希望文本框在添加新行時自動滾動到最底部的條目(最新的條目)。

如果您使用TextBox.AppendText(string text) ,它將自動滾動到新附加文本的末尾。 如果您在循環中調用它,它可以避免閃爍的滾動條。

它也恰好比連接到.Text屬性快一個數量級。 盡管這可能取決於您調用它的頻率; 我正在用一個緊密的循環進行測試。


如果在顯示文本框之前調用它,或者如果文本框不可見(例如,在 TabPanel 的不同選項卡中),則不會滾動。 請參閱TextBox.AppendText() 不自動滾動 這可能重要也可能不重要,這取決於當用戶看不到文本框時您是否需要自動滾動。

在這種情況下,其他答案中的替代方法似乎也不起作用。 一種解決方法是對VisibleChanged事件執行額外的滾動:

textBox.VisibleChanged += (sender, e) =>
{
    if (textBox.Visible)
    {
        textBox.SelectionStart = textBox.TextLength;
        textBox.ScrollToCaret();
    }
};

在內部, AppendText做這樣的事情:

textBox.Select(textBox.TextLength + 1, 0);
textBox.SelectedText = textToAppend;

但是應該沒有理由手動執行此操作。

(如果你自己反編譯它,你會發現它使用了一些可能更有效的內部方法,並且似乎是一個小特殊情況。)

您可以使用以下代碼片段:

myTextBox.SelectionStart = myTextBox.Text.Length;
myTextBox.ScrollToCaret();

這將自動滾動到最后。

.NET 4.0 中的界面似乎發生了變化。 有以下方法可以實現以上所有內容。 正如 Tommy Engebretsen 建議的那樣,將它放在 TextChanged 事件處理程序中會使其自動進行。

textBox1.ScrollToEnd();

嘗試將建議的代碼添加到 TextChanged 事件:

private void textBox1_TextChanged(object sender, EventArgs e)
{
  textBox1.SelectionStart = textBox1.Text.Length;
  textBox1.ScrollToCaret();
}
textBox1.Focus()
textBox1.SelectionStart = textBox1.Text.Length;
textBox1.ScrollToCaret();

對我不起作用(Windows 8.1,無論什么原因)。
由於我仍在使用 .NET 2.0,因此無法使用 ScrollToEnd。

但這有效:

public class Utils
{
    [System.Runtime.InteropServices.DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
    private static extern int SendMessage(System.IntPtr hWnd, int wMsg, System.IntPtr wParam, System.IntPtr lParam);

    private const int WM_VSCROLL = 0x115;
    private const int SB_BOTTOM = 7;

    /// <summary>
    /// Scrolls the vertical scroll bar of a multi-line text box to the bottom.
    /// </summary>
    /// <param name="tb">The text box to scroll</param>
    public static void ScrollToBottom(System.Windows.Forms.TextBox tb)
    {
        if(System.Environment.OSVersion.Platform != System.PlatformID.Unix)
             SendMessage(tb.Handle, WM_VSCROLL, new System.IntPtr(SB_BOTTOM), System.IntPtr.Zero);
    }


}

VB.NET:

Public Class Utils
    <System.Runtime.InteropServices.DllImport("user32.dll", CharSet := System.Runtime.InteropServices.CharSet.Auto)> _
    Private Shared Function SendMessage(hWnd As System.IntPtr, wMsg As Integer, wParam As System.IntPtr, lParam As System.IntPtr) As Integer
    End Function

    Private Const WM_VSCROLL As Integer = &H115
    Private Const SB_BOTTOM As Integer = 7

    ''' <summary>
    ''' Scrolls the vertical scroll bar of a multi-line text box to the bottom.
    ''' </summary>
    ''' <param name="tb">The text box to scroll</param>
    Public Shared Sub ScrollToBottom(tb As System.Windows.Forms.TextBox)
        If System.Environment.OSVersion.Platform <> System.PlatformID.Unix Then
            SendMessage(tb.Handle, WM_VSCROLL, New System.IntPtr(SB_BOTTOM), System.IntPtr.Zero)
        End If
    End Sub


End Class

我需要添加刷新:

textBox1.SelectionStart = textBox1.Text.Length;
textBox1.ScrollToCaret();
textBox1.Refresh();

我用這個。 簡單、干凈、快速!

txtTCPTxRx.AppendText(newText);

下面是我使用的實際代碼

ThreadSafe(() =>
      {
          string newLog = $"{DateTime.Now:HH:mm:ss:ffff->}{dLog}{Environment.NewLine}";
          txtTCPTxRx.AppendText(newLog);
      });

我發現了一個簡單的區別,在這個線程中沒有解決。

如果您將所有ScrollToCarat()調用作為表單的Load()事件的一部分進行,則它不起作用。 我剛剛將我的ScrollToCarat()調用添加到我的表單的Activated()事件中,它工作正常。

編輯

重要的是只在第一次觸發表單的Activated事件時進行滾動(而不是在后續激活時),否則每次激活表單時它都會滾動,這可能是您不想要的。

因此,如果您只是在程序加載時捕獲Activated()事件以滾動文本,那么您可以取消訂閱事件處理程序本身內的事件,因此:

Activated -= new System.EventHandler(this.Form1_Activated);

如果每次激活表單時您還有其他事情需要做,您可以在第一次觸發Activated()事件時將bool設置為 true,這樣您就不會滾動后續激活,但仍然可以執行其他操作你需要做的事情。

此外,如果您的TextBox位於不是SelectedTab的選項卡上,則ScrollToCarat()將不起作用。 因此,您至少需要在滾動時將其設為選定的選項卡。 您可以將代碼包裝在YourTab.SuspendLayout(); YourTab.ResumeLayout(false); 如果您的表格在您執行此操作時閃爍,則配對。

編輯結束

希望這可以幫助!

當文本更改時,這將滾動到文本框的末尾,但仍允許用戶向上滾動

outbox.SelectionStart = outbox.Text.Length;
outbox.ScrollToEnd();

在 Visual Studio Enterprise 2017 上測試

對於希望看到 webforms 實現的其他人,您希望使用頁面請求管理器的 endRequest 事件處理程序 ( https://stackoverflow.com/a/1388170/1830512 )。 這是我在母版頁的內容頁中為我的文本框所做的,請忽略我沒有為控件使用變量的事實:

var prm = Sys.WebForms.PageRequestManager.getInstance();

function EndRequestHandler() {
    if ($get('<%= ((TextBox)StatusWindow.FindControl("StatusTxtBox")).ClientID %>') != null) {
        $get('<%= ((TextBox)StatusWindow.FindControl("StatusTxtBox")).ClientID %>').scrollTop = 
        $get('<%= ((TextBox)StatusWindow.FindControl("StatusTxtBox")).ClientID %>').scrollHeight;
    }
}

prm.add_endRequest(EndRequestHandler);

關於皮特關於選項卡上的文本框的評論,我讓它工作的方式是添加

textBox1.SelectionStart = textBox1.Text.Length;
textBox1.ScrollToCaret();

到選項卡的布局事件。

這只對我有用...

txtSerialLogging->Text = "";

txtSerialLogging->AppendText(s);

我嘗試了上述所有情況,但問題是在我的情況下 text 可以減少,增加並且也可以長時間保持靜止。 靜態意味着,靜態長度(行)但內容不同。

所以,當長度(行)保持不變一段時間時,我最后面臨着一行跳躍的情況......

我為此使用了一個函數:

private void Log (string s) {
    TB1.AppendText(Environment.NewLine + s);
    TB1.ScrollToCaret();
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM