C# 在更新期间停止 TextBox 闪烁
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1550293/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Stopping TextBox flicker during update
提问by Bryan
My WinForms application has a TextBox that I'm using as a log file. I'm appending text without the form flickering using TextBox.AppendText(string);
, however when I try to purge old text (as the control's .Text property reaches the .MaxLength limit), I get awful flicker.
我的 WinForms 应用程序有一个用作日志文件的 TextBox。我正在使用 附加文本而没有闪烁的表单TextBox.AppendText(string);
,但是当我尝试清除旧文本时(因为控件的 .Text 属性达到 .MaxLength 限制),我得到了可怕的闪烁。
The code I'm using is as follows:
我使用的代码如下:
public static void AddTextToConsoleThreadSafe(TextBox textBox, string text)
{
if (textBox.InvokeRequired)
{
textBox.Invoke(new AddTextToConsoleThreadSafeDelegate(AddTextToConsoleThreadSafe), new object[] { textBox, text });
}
else
{
// Ensure that text is purged from the top of the textbox
// if the amount of text in the box is approaching the
// MaxLength property of the control
if (textBox.Text.Length + text.Length > textBox.MaxLength)
{
int cr = textBox.Text.IndexOf("\r\n");
if (cr > 0)
{
textBox.Select(0, cr + 1);
textBox.SelectedText = string.Empty;
}
else
{
textBox.Select(0, text.Length);
}
}
// Append the new text, move the caret to the end of the
// text, and ensure the textbox is scrolled to the bottom
textBox.AppendText(text);
textBox.SelectionStart = textBox.Text.Length;
textBox.ScrollToCaret();
}
}
Is there a neater way of purging lines of text from the top of the control that doesn't cause flickering? A textbox doesn't have the BeginUpdate()/EndUpdate() methods that a ListView has.
是否有一种更简洁的方法可以从控件顶部清除不会导致闪烁的文本行?文本框没有 ListView 具有的 BeginUpdate()/EndUpdate() 方法。
Is a TextBox control even the best suited control for a console log?
TextBox 控件甚至是最适合控制台日志的控件吗?
Edit: The TextBox flickering appears to be the textbox scrolling up to the top (while I purge the text at the top of the control), and then it immediately scrolls back down to the bottom. - it all happens very quickly, so I just see repeated flickering.
编辑:TextBox 闪烁似乎是向上滚动到顶部的文本框(同时我清除控件顶部的文本),然后它立即向下滚动到底部。- 这一切都发生得很快,所以我只看到反复闪烁。
I've also just seen this question, and the suggestion was to use a ListBox, however I don't know if this will work in my situation, as (in most cases) I'm receiving the text for the ListBox one character at a time.
我也刚看到这个问题,建议使用 ListBox,但是我不知道这是否适用于我的情况,因为(在大多数情况下)我收到 ListBox 的文本一个字符一个时间。
采纳答案by Vinko Vrsalovic
The problem is that you are adding (removing) one character at a time repeatedly and quickly. One solution would be to buffer the characters as they are being added and update the textbox at greater intervals (regardless of the amount of characters), for example, every 250 milliseconds.
问题是您一次又一次快速地添加(删除)一个字符。一种解决方案是在添加字符时缓冲它们,并以更大的间隔(无论字符数量如何)更新文本框,例如每 250 毫秒。
This would require:
这将需要:
- to have an array or stack of characters where they get added
- to have a timer that would call a delegate that would actually do the update with the characters stored in the stack
- 有一个字符数组或堆栈,它们被添加到那里
- 有一个计时器可以调用一个委托,该委托实际上会使用存储在堆栈中的字符进行更新
Another option is to use both every 250 ms and 100 chars, whatever happens first. But this would probably complicate the code more without any tangible benefit.
另一种选择是每 250 毫秒和 100 个字符同时使用,无论先发生什么。但这可能会使代码更加复杂,而没有任何实际好处。
回答by Alastair Pitts
Have you set double-buffering on your main window?
您是否在主窗口上设置了双缓冲?
this code in your constructor after the InitializeComponent call will add double buffering and possibly reduce flicker.
InitializeComponent 调用之后构造函数中的这段代码将添加双缓冲并可能减少闪烁。
this.SetStyle(
ControlStyles.AllPaintingInWmPaint |
ControlStyles.UserPaint |
ControlStyles.DoubleBuffer,true);
this.SetStyle(
ControlStyles.AllPaintingInWmPaint |
ControlStyles.UserPaint |
ControlStyles.DoubleBuffer,true);
回答by codymanix
Did you try SuspendLayout() / ResumeLayout() around all your update operations?
您是否在所有更新操作中尝试过 SuspendLayout() / ResumeLayout()?
You could also call Clear() on the textbox then reassign the truncated text.
您还可以在文本框上调用 Clear() 然后重新分配截断的文本。
If your try to implement some kind of log file viewer, you could use a ListBox instead.
如果您尝试实现某种日志文件查看器,则可以改用 ListBox。
回答by Eric
I find that using SelectedText = text will reduce the flicker dramatically. For very fast updates, the flicker will be localized to the new text only and you won't get any weird behavior from the scrollbar jumping around.
我发现使用 SelectedText = text 会显着减少闪烁。对于非常快速的更新,闪烁将仅本地化为新文本,并且滚动条不会出现任何奇怪的跳跃行为。
void UpdateTextBox(string message)
{
myTextBox.SelectionStart = myTextBox.Text.Length;
myTextBox.SelectedText = message;
}
You can also use this to overwrite text written previously -- as you would need for updating a counter or download percentage for example:
您还可以使用它来覆盖之前编写的文本——因为您需要更新计数器或下载百分比,例如:
void UpdateTextBox(string message, int jumpBack)
{
myTextBox.SelectionStart = Math.Max(myTextBox.Text.Length - jumpBack, 0);
myTextBox.SelectionLength = jumpBack;
myTextBox.SelectedText = message;
}
Other than that, there doesn't seem to be any simple method for reducing flicker in the .NET TextBox.
除此之外,似乎没有任何简单的方法可以减少 .NET TextBox 中的闪烁。
回答by Mathijs Beentjes
I found a solution looking on the internet:
我在网上找到了一个解决方案:
[System.Runtime.InteropServices.DllImport("user32.dll")]
public static extern bool LockWindowUpdate(IntPtr hWndLock);
internal void FillTB(TextBox tb, string mes)
{
try
{
LockWindowUpdate(tb.Handle);
// Do your thingies with TextBox tb
}
finally
{
LockWindowUpdate(IntPtr.Zero);
}
}
回答by mkaj
Mathijs answer is works for me. I've modified it slightly so I can use with any control - a control extension:
Mathijs 的回答对我有用。我稍微修改了它,所以我可以使用任何控件 - 控件扩展:
namespace System.Windows.Forms
{
public static class ControlExtensions
{
[System.Runtime.InteropServices.DllImport("user32.dll")]
public static extern bool LockWindowUpdate(IntPtr hWndLock);
public static void Suspend(this Control control)
{
LockWindowUpdate(control.Handle);
}
public static void Resume(this Control control)
{
LockWindowUpdate(IntPtr.Zero);
}
}
}
So all you need to do is:
所以你需要做的就是:
myTextBox.Suspend();
// do something here.
myTextBox.Resume();
Works well. All flickering stops.
效果很好。所有闪烁停止。