19

有很多文章解决了 Windows 窗体中的闪烁问题。大多数人建议设置DoubleBuffered = true或设置一堆ControlStyle标志。但是,这些都不能帮助减少 TextBox 闪烁。

这里有几个相关的问题:

要重现此问题,请创建一个新的 WinForms 项目,添加一个TextBox,启用多行,禁用自动换行,添加一堆文本,设置Anchor为 Left+Right+Top+Bottom。现在运行并调整大小。文字闪烁。对于几个嵌套TableLayoutPanels 内的文本框,调整大小时的闪烁甚至更糟。

应用上述问题中提出的解决方案充其量不会解决闪烁问题;如果我进行实验并设置保护ControlStyleTextBox我可以完全打破它(通过启用UserPaint)但不能消除闪烁。

那么,有什么办法可以修复TextBox中文本的闪烁问题吗?

4

4 回答 4

16

我通常使用RichTextBox而不是多行文本框。通过将 DetectUrls- 和 ShortcutsEnabled-properties 设置为 false,RTB 的行为与 TextBox 非常相似,并且......它是无闪烁的

于 2011-04-15T14:45:17.080 回答
4

在 Windows 窗体中,DoubleBuffered 属性不会影响子控件,例如文本框。相反,它只影响为其设置的表单或面板。

如果要对表单上的子元素进行双缓冲,则需要实现手动双缓冲。

Bob Powell 写了一篇关于如何做到这一点的好文章(和其他文章)。

此外,从论坛回答鲍勃还说:

窗口的所有权意味着它们会不受控制地闪烁,因为您不能在目标窗口区域之外进行双重缓冲。例如,不能使具有子控件的面板对自身进行双重缓冲,并且 它是子控件。

正确执行此操作的唯一方法是创建一个使用保留模式图形系统形式进行所有绘图的单个控件。

因此,要使用手动双缓冲来调整无闪烁文本框的大小,您需要以某种方式将文本框渲染到后台缓冲区,然后将其显示为缓冲更新的一部分。如果可能的话:我不认为这会很容易。

[更新]

其他一些答案说这是专门针对 Windows 窗体的问题。这是不正确的,它实际上比这更深,是由 Windows GDI 引起的。例如,打开记事本/写字板等并粘贴一大块文本,调整窗口大小,并注意到同样的闪烁问题。

这是我多年前用来做类似事情的基本解决方案。它是一个简单的表单,包含一个多行文本框和一个继承自 Panel 的自定义类。两个控件具有相同的位置和大小。它使用 Forms ResizeBegin 和 ResizeEnd 在调整大小时显示面板,否则显示文本框。它并不完美,但它确实消除了闪烁。

   public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        Bitmap bm = null;

        private void textBox1_Resize(object sender, EventArgs e)
        {

            Graphics g = textBox1.CreateGraphics();

            if (g.VisibleClipBounds.IsEmpty == false)
            {
                bm = new Bitmap((int)g.VisibleClipBounds.Width, (int)g.VisibleClipBounds.Height);

                textBox1.DrawToBitmap(bm, new Rectangle(0, 0, (int)g.VisibleClipBounds.Width, (int)g.VisibleClipBounds.Height));

            }

            g.Dispose();


        }

        private void panelDB1_Paint(object sender, PaintEventArgs e)
        {
            if (bm != null)
            {
                e.Graphics.DrawImageUnscaled(bm, 0, 0,bm.Width,bm.Height );
            }
        }

        private void Form1_ResizeBegin(object sender, EventArgs e)
        {
            panelDB1.BringToFront();  
        }

        private void Form1_ResizeEnd(object sender, EventArgs e)
        {
            panelDB1.SendToBack();   
        }
}

class PanelDB : Panel
{
    public PanelDB()
    {
        this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.OptimizedDoubleBuffer,true);       
        //this.DoubleBuffered = true; 
    
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        base.OnPaint(e);
    }
}
于 2009-08-26T09:59:14.920 回答
0

我们过去也遇到过同样的问题,结果是使用了过多的停靠和表格布局面板。如果可能的话,我会建议尝试使用最少的停靠来重新构建 UI(因为表格布局面板也在内部使用停靠)。

于 2009-08-26T09:52:18.663 回答
-3

FUNCTION LockWindow AS LONG CONTROL SEND ghDlg, %TEXT_UPPER,%WM_SETREDRAW,0,0 CLEARBuffers END FUNCTION

FUNCTION UnlockWindow AS LONG ClearBuffers CONTROL SEND ghDlg,%TEXT_UPPER,%WM_SETREDRAW,1,0 END FUNCTION

于 2015-12-01T04:53:04.327 回答