2014-10-27 72 views
2

我已经开始制作一个小型项目的主服务器程序,涉及在较新的引擎上重建游戏。 主服务器程序目前看起来像这样:自动滚动到多行文本框的底部

enter image description here

大型文本框用“找到4安装的处理器(多个)”是一个“控制台”,其输出发送到和来自客户端/游戏服务器生的事件消息使用主服务器。它不能被输入并且管理员(唯一可以访问主服务器程序的这个接口的人)只能从文本框中复制;他们不能删除/添加任何东西。

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

关于堆栈溢出的问题有很多,例如: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 
+1

你是什么意思是行不通的。您不应该在TextChanged事件中调用AppendText,因为它会导致非停止循环。 'AppendText'会触发'TextChanged'增加另一个'AppendText',然后触发'TextChanged'等等。这将会持续下去。 – 2014-10-27 11:47:23

+0

@SriramSakthivel这将解释为什么该程序的标题被附加到每一行很多。我在哪里/如何正确地做到这一点?编辑补充说,当我使用该代码时,文本框不滚动。 – cybermonkey 2014-10-27 11:48:37

+1

我无法重现该问题。如果你只是单独使用'AppendText',那就行得通了(我的意思是正确的滚动)。发布一些简短但完整的样本来重现问题。 – 2014-10-27 11:55:23

回答

1

如果您使用AppendText,你可以完全摆脱console_TextChanged方法,因为AppendText已经这样做了你。

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

作为解决方法,只需将所有代码移至MyBase.Shown事件,而不是Load事件。如预期的那样,差异是Shown事件将在屏幕上第一次呈现时立即被提升,而在呈现表单之前被触发的Load会立即发生。

1

你可以做到这一点在加载事件但它是更为复杂:

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 
1

使用RichTextBox,而不是一个TextBox你可以使用的:

<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后这段代码。

'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 
0

还有一个有用的解决方案:

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

它只是把光标在文本框中的文本的结束和滚动到当前光标位置。为我完美工作!