自动滚动到多行文本框的底部

时间:2014-10-27 11:35:16

标签: vb.net winforms textbox visual-studio-2015

我已经开始为一个涉及在较新引擎上重建游戏的小项目制作主服务器程序。 主服务器程序目前看起来像这样:

enter image description here

带有“找到4个已安装处理器”的大型文本框'是一个控制台'它使用主服务器输出发送到客户端/游戏服务器的原始事件消息。它无法输入,管理员(唯一有权访问主服务器程序接口的人)只能从文本框中复制;他们无法删除/添加任何内容。

问题在于,因为它应该是一个'控制台,它应该会自动向下滚动到多行文本框的最后一行。

Stack Overflow上有很多问题可以解决这个问题(例如this one),但是当我放置它时,我还没有能够让它工作(文本框不会向下滚动) console_TextChanged子例程中的代码。 我试过这个:

Private Sub console_TextChanged(sender As Object, e As EventArgs) Handles console.TextChanged
    console.AppendText(Text)
    console.Select(console.TextLength, 0)
    console.ScrollToCaret()
End Sub

它不起作用,但它会导致程序中的错误,其中每行都会多次附加程序的标题:

[net 11:32:22.243] System Started.Server Network | Crysis Wars 1.5Server Network | Crysis Wars 1.5Server Network | Crysis Wars 1.5Server Network | Crysis Wars 1.5Server Network | Crysis Wars 1.5Server Network | Crysis Wars 1.5Server Network | Crysis Wars 1.5Server Network | Crysis Wars 1.5Server Network | Crysis Wars 1.5Server Network | Crysis Wars 1.5

过去,一些C#解决方案在Visual Basic .Net中也适用于我,因此我尝试了some of the ones on Stack Overflow,但我也无法使这些工作正常工作。

这是否是自动滚动多线文本框的正确方法,如果是这样,为什么它对我不起作用?

完整(相关)代码:

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    console.Text = GetNetTime() + "System Started."
    WriteToConsole("Working Area: " + CStr(My.Computer.Screen.WorkingArea().Width) + "*" + CStr(My.Computer.Screen.WorkingArea().Height))
    WriteToConsole("Found " + CStr(Environment.ProcessorCount) + " installed processor(s)")
    Dim i As Integer = 0
    While (i < Environment.ProcessorCount)
        WriteToConsole("Processor " + CStr(i) + ": " + My.Computer.Registry.LocalMachine.OpenSubKey("Hardware\Description\System\CentralProcessor\" + CStr(i)).GetValue("ProcessorNameString"))
        WriteToConsole("            Family: " + My.Computer.Registry.LocalMachine.OpenSubKey("Hardware\Description\System\CentralProcessor\" + CStr(i)).GetValue("Identifier"))
        WriteToConsole("            Manufacturer: " + My.Computer.Registry.LocalMachine.OpenSubKey("Hardware\Description\System\CentralProcessor\" + CStr(i)).GetValue("VendorIdentifier"))
        i += 1
    End While
    WriteToConsole("Starting networking services")
End Sub
Private Sub console_TextChanged(sender As Object, e As EventArgs) Handles console.TextChanged
    console.AppendText(Text)
    console.Select(console.TextLength, 0)
    console.ScrollToCaret()
End Sub
Function GetNetTime()
    Return "[net " + CStr(DateTime.UtcNow.Hour) + ":" + CStr(DateTime.UtcNow.Minute) + ":" + CStr(DateTime.UtcNow.Second) + "." + CStr(DateTime.UtcNow.Millisecond) + "] "
End Function
Function WriteToConsole(ByVal input As String)
    console.AppendText(Environment.NewLine & GetNetTime() + input)
    Return -1
End Function

4 个答案:

答案 0 :(得分:2)

如果您正在使用AppendText,则可以完全摆脱console_TextChanged方法,因为AppendText已经为您执行此操作。

出于某种原因(可能是错误?)当TextBox没有暴露在屏幕上时,AppendText似乎无法滚动到结束。我现在没有好的解释,需要查看.Net框架源。

作为一种解决方法,只需将所有代码移至MyBase.Shown事件,而不是Load事件。这是按预期工作的,差异是Shown事件将在屏幕首次呈现时立即引发,而不是Load在呈现表单之前被触发。

答案 1 :(得分:1)

您可以在加载事件中执行此操作,但它更复杂:

<DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
Private Shared Function SendMessage(ByVal hWnd As IntPtr, ByVal Msg As UInteger, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr
End Function

textbox中设置文字后:

If (console.IsHandleCreated) Then
    'set focus
    SendMessage(console.Handle, &H7, IntPtr.Zero, IntPtr.Zero) 'WM_SETFOCUS
    'move caret to the end
    SendMessage(console.Handle, &HB1, CType(-1, IntPtr), CType(-1, IntPtr)) 'EM_SETSEL
    'scroll to the end
    SendMessage(console.Handle, &HB6, IntPtr.Zero, CType(console.Lines.Length, IntPtr)) 'EM_LINESCROLL
Else
    MsgBox("console window is not created")
End If

答案 2 :(得分:1)

使用RichTextBox代替TextBox,您可以使用此代码。

'SENDMESSAGE constants
'move to the last row in a RichTextBox
'you can obtain the same effect using ScrollToCaret but it works only if Focus is on RichTextBox
Private Const WM_VSCROLL As Int32 = &H115
Private Const SB_BOTTOM As Int32 = 7

Private Sub WriteLog(ByVal strLineLog As String)

    If Me.rtbLog.Text = "" Then
        Me.rtbLog.Text = strLineLog
    Else
        Me.rtbLog.AppendText(System.Environment.NewLine & strLineLog)
    End If

    SendMessage(Me.rtbLog.Handle, WM_VSCROLL, SB_BOTTOM, 0)

End Sub

答案 3 :(得分:1)

一个更有用的解决方案:

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

它只是将光标放在文本框中的文本末尾并滚动到当前光标位置。完美地为我工作!