在输入/复制到富文本框时防止闪烁

出于颜色编码的原因,我需要一个系统,我经常将一个字符串粘贴到一个富文本框(而不是默认的标准输入)。 不幸的是,它经常会导致闪光,特别是如果你保持按住键。

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;
    }
}

您不需要刷新每个按键的RTB,这是您在没有任何Application.DoEvents()调用的情况下处理TextChanged时发生的情况。

我发现获得可接受性能的最佳方式是处理KeyDown事件。 如果keycode(带修饰符)是一个可打印的字符,我会启动一个定时器,它的Tick事件处理程序在100ms后检查richtextbox的文本。

因为当触发KeyDown事件时,类型化字符没有被打印,你可以通过设置SelectionColor属性(不改变代码中的选择),实际上在这个事件处理程序中修改这个字符的文本颜色,所以你不需要需要冻结控制。 不要试图在这方面做太多的处理器密集型的东西,因为你会得到响应问题。

最后,修改RichTextBox的行为是一个sprial,只要你偏离了规范,你将开始使用自定义代码来执行通常使用控件自身功能执行的各种任务(如复制/粘贴撤销/重做和滚动) 。 然后,您可以决定是继续自己还是去参加第三方编辑。 还要注意的是,虽然你已经开始使用Windows API了,但是对于滚动,打印和绘画事件来说,还有更多的事情,特别是尽管有很好的在线资源记录这些事件。

不要让这让你灰心,只要知道如果你的应用程序需求增长,未来会如何。


最近我遇到了类似的问题。 我选择的方法是将扩展方法添加到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();
    }
}
链接地址: http://www.djcxy.com/p/61995.html

上一篇: Prevent flashing whilst typing/copying to rich text box

下一篇: Resize WinForms UserControl