Maintain Textbox Scroll Position
-
Hi, I'm outputting some logging output to a TextBox, using the following code:
public void AddNewMessage( String message ) { lock (this) { if (disposed) throw new ObjectDisposedException( "PeerMessagesDisplay" ); String text = this.textBox1.Text.Insert( this.textBox1.Text.Length, message ); SetText( text ); } } private void SetText( String text ) { if (this.InvokeRequired) this.textBox1.Invoke( new Action( SetTextHelper ), text ); else SetTextHelper( text ); } private void SetTextHelper( String text ) { this.textBox1.Text = text; }
But, whenever text is appended to the textbox, it automatically scrolls up to the top. This is bad when I'm trying to observe the output at the bottom or somewhere in the middle. How can I maintain the textbox's scroll position? Thanks, klk
madness ? this.isSparta = true : this.isSparta = false;
-
Hi, I'm outputting some logging output to a TextBox, using the following code:
public void AddNewMessage( String message ) { lock (this) { if (disposed) throw new ObjectDisposedException( "PeerMessagesDisplay" ); String text = this.textBox1.Text.Insert( this.textBox1.Text.Length, message ); SetText( text ); } } private void SetText( String text ) { if (this.InvokeRequired) this.textBox1.Invoke( new Action( SetTextHelper ), text ); else SetTextHelper( text ); } private void SetTextHelper( String text ) { this.textBox1.Text = text; }
But, whenever text is appended to the textbox, it automatically scrolls up to the top. This is bad when I'm trying to observe the output at the bottom or somewhere in the middle. How can I maintain the textbox's scroll position? Thanks, klk
madness ? this.isSparta = true : this.isSparta = false;
Use the AppendText method on the TextBox. I think that maintains the scroll position.
"An eye for an eye only ends up making the whole world blind"
-
Use the AppendText method on the TextBox. I think that maintains the scroll position.
"An eye for an eye only ends up making the whole world blind"
-
Hey Rob, This is a better solution, you are right. Unfortunately, it still always keeps the textbox's scroll position locked at the bottom. Is there a way around that? klk
madness ? this.isSparta = true : this.isSparta = false;
Hi klk, I tried a couple of things here to try & get this working! Simplest solution is to use the SelectionStart property, although this is still not ideal... Try this:
Dim i As Integer = TextBox1.SelectionStart Dim atEnd As Boolean = i >= TextBox1.Text.Length TextBox1.AppendText("New line: " + TextBox1.Text.Length.ToString() + vbNewLine) If Not atEnd Then TextBox1.SelectionStart = i TextBox1.ScrollToCaret() End If
Other than this, you could look at using the native scroll functions (GetScrollInfo, SetScrollInfo) - see google & msdn for more info about these. Hope this helps! Rob
"An eye for an eye only ends up making the whole world blind"
-
Hi klk, I tried a couple of things here to try & get this working! Simplest solution is to use the SelectionStart property, although this is still not ideal... Try this:
Dim i As Integer = TextBox1.SelectionStart Dim atEnd As Boolean = i >= TextBox1.Text.Length TextBox1.AppendText("New line: " + TextBox1.Text.Length.ToString() + vbNewLine) If Not atEnd Then TextBox1.SelectionStart = i TextBox1.ScrollToCaret() End If
Other than this, you could look at using the native scroll functions (GetScrollInfo, SetScrollInfo) - see google & msdn for more info about these. Hope this helps! Rob
"An eye for an eye only ends up making the whole world blind"
Hey Rob, I tried that solution, but the
SelectionStart
property refers to where the cursor is, not the scrollbar. Basically, unless the user clicks inside the textbox to place the cursor somewhere, it doesn't work. I looked up the P/Invoke stuff for Get/SetScrollInfo, but that's not working either! It still always jumps down to the bottom of the textbox. Here's my refactored code:public partial class PeerMessagesDisplay : Form { #region ScrollInfo \[DllImport( "user32.dll" )\] \[return: MarshalAs( UnmanagedType.Bool )\] private static extern bool GetScrollInfo( IntPtr hwnd, int fnBar, ref SCROLLINFO lpsi ); \[DllImport( "user32.dll" )\] static extern int SetScrollInfo( IntPtr hwnd, int fnBar, \[In\] ref SCROLLINFO lpsi, bool fRedraw ); \[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; } private enum ScrollBarDirection { SB\_HORZ = 0, SB\_VERT = 1, SB\_CTL = 2, SB\_BOTH = 3 } private enum ScrollInfoMask { 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 } #endregion private String title; private String logFile; private bool disposed; public PeerMessagesDisplay( String title, String logFilePath ) { InitializeComponent(); this.title = title; this.logFile = logFilePath; this.Show(); } public void LoadLog( ) { ThreadPool.QueueUserWorkItem( delegate { try { if (this.InvokeRequired) this.BeginInvoke( new Action( delegate( String s ) { this.Text = s; } ), title ); else this.Text = title; using (FileStream fs = File.OpenRead( this.logFile )) { using (StreamReader reader = new StreamReader( fs ))
-
Hey Rob, I tried that solution, but the
SelectionStart
property refers to where the cursor is, not the scrollbar. Basically, unless the user clicks inside the textbox to place the cursor somewhere, it doesn't work. I looked up the P/Invoke stuff for Get/SetScrollInfo, but that's not working either! It still always jumps down to the bottom of the textbox. Here's my refactored code:public partial class PeerMessagesDisplay : Form { #region ScrollInfo \[DllImport( "user32.dll" )\] \[return: MarshalAs( UnmanagedType.Bool )\] private static extern bool GetScrollInfo( IntPtr hwnd, int fnBar, ref SCROLLINFO lpsi ); \[DllImport( "user32.dll" )\] static extern int SetScrollInfo( IntPtr hwnd, int fnBar, \[In\] ref SCROLLINFO lpsi, bool fRedraw ); \[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; } private enum ScrollBarDirection { SB\_HORZ = 0, SB\_VERT = 1, SB\_CTL = 2, SB\_BOTH = 3 } private enum ScrollInfoMask { 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 } #endregion private String title; private String logFile; private bool disposed; public PeerMessagesDisplay( String title, String logFilePath ) { InitializeComponent(); this.title = title; this.logFile = logFilePath; this.Show(); } public void LoadLog( ) { ThreadPool.QueueUserWorkItem( delegate { try { if (this.InvokeRequired) this.BeginInvoke( new Action( delegate( String s ) { this.Text = s; } ), title ); else this.Text = title; using (FileStream fs = File.OpenRead( this.logFile )) { using (StreamReader reader = new StreamReader( fs ))
Hi, you need to set the cbSize and fMask fields before calling GetScrollInfo. Try using:
scrollInfo.cbSize = Marshal.SizeOf(SCROLLINFO);
scrollInfo.fMask = ScrollInfoMask.SIF_POS;I think this should work, but havn't tried it... Rob
"An eye for an eye only ends up making the whole world blind"
-
Hi, I'm outputting some logging output to a TextBox, using the following code:
public void AddNewMessage( String message ) { lock (this) { if (disposed) throw new ObjectDisposedException( "PeerMessagesDisplay" ); String text = this.textBox1.Text.Insert( this.textBox1.Text.Length, message ); SetText( text ); } } private void SetText( String text ) { if (this.InvokeRequired) this.textBox1.Invoke( new Action( SetTextHelper ), text ); else SetTextHelper( text ); } private void SetTextHelper( String text ) { this.textBox1.Text = text; }
But, whenever text is appended to the textbox, it automatically scrolls up to the top. This is bad when I'm trying to observe the output at the bottom or somewhere in the middle. How can I maintain the textbox's scroll position? Thanks, klk
madness ? this.isSparta = true : this.isSparta = false;
Hi, for displaying log information I prefer a ListBox over a TextBox. For one, it is much faster, since it keeps all the text lines apart, it never needs them all concatenated. Furthermore, it has a TopIndex property, which determines the scroll state. So a typical log method would consist of:
void log(string s) {
lb.Items.Add(s);
lb.TopIndex=lb.Items.Count-1;
}:)
Luc Pattyn [Forum Guidelines] [My Articles]
Voting for dummies? No thanks. X|
-
Hi, for displaying log information I prefer a ListBox over a TextBox. For one, it is much faster, since it keeps all the text lines apart, it never needs them all concatenated. Furthermore, it has a TopIndex property, which determines the scroll state. So a typical log method would consist of:
void log(string s) {
lb.Items.Add(s);
lb.TopIndex=lb.Items.Count-1;
}:)
Luc Pattyn [Forum Guidelines] [My Articles]
Voting for dummies? No thanks. X|
-