出于颜色编码的原因,我需要一个系统,我经常将一个字符串粘贴到一个富文本框(而不是默认的标准输入)。不幸的是,它经常会导致闪光,特别是如果你按住键的话。
RTB似乎不支持双缓冲,但我不确定这是否会有所帮助。超越油漆事件也似乎无效。在研究了网络之后,到目前为止我发现的最好的“解决方案”是使用本机Windows互操作(LockWindowUpdate等)。这样可以解决滚动点以外打字非常可怕的情况。不幸的是,现在仍然存在(较小的)闪烁。
下面的代码可以立即编译(只需创建一个控制台项目并引用System.Windows.Forms和System.Drawing)。如果你这样做,按一个键,并保持按住,比如10行值。如果你这样做,你会注意到越来越多的闪烁出现。键入的越多,闪烁就越差。
using System; using System.Windows.Forms; using System.Runtime.InteropServices; namespace FlickerTest { public partial class Form1 : Form { public Form1() { InitializeComponent(); } [DllImport("user32.dll")] public static extern bool LockWindowUpdate(IntPtr hWndLock); private void rtb_TextChanged(object sender, EventArgs e) { String s = rtb.Text; LockWindowUpdate(rtb.Handle); rtb.Text = s; rtb.Refresh(); ////Forces a synchronous redraw of all controls LockWindowUpdate(IntPtr.Zero); } } ////////////////////////////////////////////////// // Ignore below: static class Program { [STAThread] static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new Form1()); } } partial class Form1 { private System.ComponentModel.IContainer components = null; protected override void Dispose(bool disposing) { if (disposing && (components != null)) components.Dispose(); base.Dispose(disposing); } #region Windows Form Designer generated code private void InitializeComponent() { this.rtb = new System.Windows.Forms.RichTextBox(); this.SuspendLayout(); // rtb this.rtb.BackColor = System.Drawing.Color.Black; this.rtb.Font = new System.Drawing.Font("Microsoft Sans Serif", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.rtb.ForeColor = System.Drawing.SystemColors.Window; this.rtb.Location = new System.Drawing.Point(24, 20); this.rtb.Name = "rtb"; this.rtb.Size = new System.Drawing.Size(609, 367); this.rtb.TabIndex = 0; this.rtb.Text = ""; this.rtb.TextChanged += new System.EventHandler(this.rtb_TextChanged); // Form1 this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(1088, 681); this.Controls.Add(this.rtb); this.Name = "Form1"; this.Text = "Form1"; this.ResumeLayout(false); } #endregion private System.Windows.Forms.RichTextBox rtb; } }
答案 0 :(得分:1)
您不需要为每次按键刷新RTB,这是在没有任何Application.DoEvents()调用的情况下处理TextChanged时发生的情况。
我发现获得可接受性能的最佳方法是处理KeyDown事件。如果keycode(带修饰符)是一个可打印的字符,我启动一个计时器,其Tick事件处理程序在说100ms之后检查richtextbox的文本。
因为当触发KeyDown事件时,尚未打印键入的char,您可以通过设置SelectionColor属性(不更改代码中的选择)来实际修改此事件处理程序中此char的文本颜色,因此您不需要冻结控件。不要尝试在这方面做太多处理器密集型的事情,因为你会得到响应问题。
最后,修改RichTextBox行为是一个sprial,一旦你偏离规范,你将开始使用自定义代码进行各种任务(如复制/粘贴撤消/重做和滚动),这些任务通常会使用控制自己的功能。然后,您决定是继续自己还是去第三方编辑。另请注意,虽然您已经开始使用Windows API,但是对于滚动,打印和绘制事件,尤其会有更多这样的内容,尽管有很好的在线资源可以记录这些内容。
不要让这一点让人气馁,只要知道如果您的应用程序需求增长,未来会发生什么。
答案 1 :(得分:1)
我最近遇到了类似的问题。我选择的方法是将扩展方法添加到richtextbox。我喜欢这种方法,因为它清洁,包含,并且易于重复使用。
这使得暂停重绘就像
一样简单richtextbox.SuspendDrawing();
并恢复
richtextbox.ResumeDrawing()
public static class RichTextBoxExtensions
{
[DllImport("user32.dll")]
private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);
private const int WM_SETREDRAW = 0x0b;
public static void SuspendDrawing(this System.Windows.Forms.RichTextBox richTextBox)
{
SendMessage(richTextBox.Handle, WM_SETREDRAW, (IntPtr)0, IntPtr.Zero);
}
public static void ResumeDrawing(this System.Windows.Forms.RichTextBox richTextBox)
{
SendMessage(richTextBox.Handle, WM_SETREDRAW, (IntPtr)1, IntPtr.Zero);
richTextBox.Invalidate();
}
}