winforms标签闪烁

时间:2010-09-28 19:34:01

标签: c# .net winforms label flicker

我的Label控件出现问题,非常闪烁。

下面是一些重现问题的代码。

如何解决这个问题?

更新:前一种情况的解决方案(表单直接包含标签)是使form.DoubleBuffered = true。但这不是一般的解决方案。例如,对于SplitContainer中的标签,我该怎么办?这是我的真实案例。

更新代码:

DoubleBufferedLabel.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace FlickerLabelTest
{
    public class DoubleBufferedLabel : Label
    {
        public DoubleBufferedLabel()
        {
            DoubleBuffered = true;
        }
    }
}

DoubleBufferedSplitContainer.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace FlickerLabelTest
{
    public class DoubleBufferedSplitContainer : SplitContainer
    {
        public DoubleBufferedSplitContainer()
        {
            DoubleBuffered = true;
        }
    }
}

Form1.cs中:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

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

        private void timer1_Tick(object sender, EventArgs e)
        {
            label1.Text += "0";
        }
    }
}

Form1.Designer.cs:

namespace FlickerLabelTest
{
    partial class Form1
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.components = new System.ComponentModel.Container();
            this.timer1 = new System.Windows.Forms.Timer(this.components);
            this.label1 = new FlickerLabelTest.DoubleBufferedLabel();
            this.splitContainer1 = new DoubleBufferedSplitContainer();
            this.splitContainer1.Panel2.SuspendLayout();
            this.splitContainer1.SuspendLayout();
            this.SuspendLayout();
            // 
            // timer1
            // 
            this.timer1.Enabled = true;
            this.timer1.Interval = 1;
            this.timer1.Tick += new System.EventHandler(this.timer1_Tick);
            // 
            // label1
            // 
            this.label1.Dock = System.Windows.Forms.DockStyle.Fill;
            this.label1.Location = new System.Drawing.Point(0, 0);
            this.label1.Name = "label1";
            this.label1.Size = new System.Drawing.Size(186, 262);
            this.label1.TabIndex = 0;
            this.label1.Text = "label1";
            // 
            // splitContainer1
            // 
            this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill;
            this.splitContainer1.Location = new System.Drawing.Point(0, 0);
            this.splitContainer1.Name = "splitContainer1";
            // 
            // splitContainer1.Panel2
            // 
            this.splitContainer1.Panel2.Controls.Add(this.label1);
            this.splitContainer1.Size = new System.Drawing.Size(284, 262);
            this.splitContainer1.SplitterDistance = 94;
            this.splitContainer1.TabIndex = 1;
            // 
            // Form1
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(284, 262);
            this.Controls.Add(this.splitContainer1);
            this.DoubleBuffered = true;
            this.Name = "Form1";
            this.Text = "Form1";
            this.WindowState = System.Windows.Forms.FormWindowState.Maximized;
            this.splitContainer1.Panel2.ResumeLayout(false);
            this.splitContainer1.ResumeLayout(false);
            this.ResumeLayout(false);

        }

        #endregion

        private System.Windows.Forms.Timer timer1;
        private DoubleBufferedLabel label1;
        private DoubleBufferedSplitContainer splitContainer1;
    }
}

的Program.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;

namespace FlickerLabelTest
{
    static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
        }
    }
}

7 个答案:

答案 0 :(得分:10)

问题在于对接。如果您将Label.DockFill更改为None,请手动设置标签的大小以填充拆分面板,然后将其锚定在所有方面,它不会闪烁。

如果您想查看闪烁的原因,Dock仍设置为Fill,请覆盖OnResize课程中的DoubleBufferedLabel,启动应用程序,正在运行时在OnResize中设置断点。添加Size的监视,您会看到它在设计时和运行时大小之间翻转。

我尝试在您的示例中使用常规SplitContainerLabel,在表单上将DoubleBuffer设置为False,如果我离开{{1,则不会闪烁在Dock上设置为None

答案 1 :(得分:2)

将其粘贴到您的表单代码中以帮助Dock布局计算:

    protected override void OnLoad(EventArgs e) {
        label1.Size = this.ClientSize;
        base.OnLoad(e);
    }

答案 2 :(得分:1)

不是真的答案,但为什么要更新标签每毫秒? 如果您的意思是1秒,则必须将间隔设置为1000.

你可以通过给表单时间重绘自己并使用更大的间隔来解决这个问题。

更新:结果显示,将 DoubleBuffered 设置为true可解决问题。感谢csharptest.net指出这一点,并DxCK来纠正我。

答案 3 :(得分:1)

我认为你正在寻找:http://msdn.microsoft.com/en-us/library/3t7htc9c.aspx

示例:

class Form1 : Form
{
   public Form1() {
      this.DoubleBuffered = true;
   }
}

答案 4 :(得分:0)

停止将定时器设置为1ms。没有认真的,你在这里看到的是标签试图跟上它的变化,但没有这样做,因为它们经常发生。所以可能的解决方案是:

  • 选择一种不经常更改标签的方法
  • 在表单上激活双缓冲

答案 5 :(得分:0)

为什么不通过异步委托运行标签更新功能?或者使用System.Threading命名空间来获得不同的风格。

另外,正如我之前提到的那样,如果你将表单上的DoubleBuffer属性设置为true(虽然它不是银弹)会很有用。

答案 6 :(得分:0)

激活表单上的双缓冲将解决问题。但这实际上是一种昂贵的解决方案。如果您只是将以下内容添加到表单中:

 SetStyle(ControlStyles.AllPaintingInWmPaint, true);

闪烁也将结束。

Windows操作系统的默认行为首先让所有窗口绘制背景,然后让它们进行实际绘制。这是过去,当时绘画字母实际上花了相当多的时间。该标志告诉它紧接着相互折叠背景颜料和常规颜料(对于同一窗口)。

真正的双重缓冲可以保留用于您实际自己绘画的情况(当您重写OnPaint时)。