2

我有一个非常闪烁的标签控件问题。

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

如何解决这个问题?

更新:前一种情况的解决方案(表单直接包含标签)是使 form.DoubleBuffered = true。但这不是一个通用的解决方案。比如SplitContainer里面有label怎么办?这是我的真实情况。

更新代码:

双缓冲标签.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;
    }
}

程序.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());
        }
    }
}
4

7 回答 7

10

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

如果您想查看闪烁的原因,whileDock仍设置为,请在您的 类中Fill覆盖,启动应用程序,并在运行时在. 添加一个监视,您会看到它在其设计时间和运行时大小之间翻转。OnResizeDoubleBufferedLabelOnResizeSize

我尝试使用常规SplitContainerLabel在您的示例中,在表单上设置为,如果DoubleBuffer我在.FalseDockNoneLabel

于 2010-09-29T00:34:54.423 回答
2

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

例子:

class Form1 : Form
{
   public Form1() {
      this.DoubleBuffered = true;
   }
}
于 2010-09-28T19:42:22.237 回答
2

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

    protected override void OnLoad(EventArgs e) {
        label1.Size = this.ClientSize;
        base.OnLoad(e);
    }
于 2010-09-28T19:46:50.630 回答
1

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

您可以通过给表单时间重新绘制自身并使用更大的间隔来解决此问题。

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

于 2010-09-28T19:40:42.237 回答
1

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

 SetStyle(ControlStyles.AllPaintingInWmPaint, true);

闪烁也会结束。

Windows 操作系统的默认行为是首先让所有窗口绘制背景,然后让它们进行实际绘制。这是从过去开始的,当时画字母实际上需要相当长的时间。这个标志告诉它在彼此之后立即折叠背景油漆和常规油漆(对于同一窗口)。

真正的双缓冲可以保留给您自己实际绘制的情况(当您覆盖 OnPaint 时)。

于 2010-09-28T20:06:56.887 回答
0

停止将定时器设置为 1ms。不认真,你在这里看到的是标签试图跟上它的变化,但因为它们太频繁而未能这样做。所以可能的解决方案是:

  • 选择一种减少标签更改频率的方法
  • 在表单上激活双缓冲
于 2010-09-28T19:42:09.503 回答
0

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

此外,正如我之前提到的那样,如果您将表单上的 DoubleBuffer 属性设置为 true,这将很有用(虽然这不是灵丹妙药)。

于 2010-09-28T19:47:20.917 回答