【问题标题】:How to use the Control.Update method in a custom control如何在自定义控件中使用 Control.Update 方法
【发布时间】:2012-06-09 05:04:16
【问题描述】:

我将先发布我的代码,因为它简短易懂,然后我会问我的问题。

public class BatteryLabel : Control
{
    private Color _captionColor = SystemColors.Control;
    private Color _textColor = SystemColors.Info;
    private Color _failColor = Color.Red;
    private Color _passColor = Color.Green;
    private string _caption;
    string text2;
    string text3;
    bool battery1Fail = false;
    bool battery2Fail = false;
    bool battery3Fail = false;

    public BatteryLabel()
    {

    }

    public Color BackgroundTextColor
    {
        get{ return _textColor;}
        set{_textColor = value; Invalidate();}
    }

    public string Caption
    {
        get
        {
            return _caption;
        }
        set
        {
            _caption = value;
            Invalidate();
        }
    }

    public override string Text
    {
        get
        {
            return base.Text;
        }
        set
        {
            base.Text = value;
            Invalidate();
        }
    }

    public string Text2
    {
        get { return text2; }
        set { text2 = value; Invalidate(); }
    }

    public string Text3
    {
        get { return text3; }
        set { text3 = value; Invalidate(); }
    }

    public bool Battery1Fail
    {
        get { return battery1Fail; }
        set { battery1Fail = value; Invalidate(); }
    }

    public bool Battery2Fail
    {
        get { return battery2Fail; }
        set { battery2Fail = value; Invalidate(); }
    }

    public bool Battery3Fail
    {
        get { return battery3Fail; }
        set { battery3Fail = value; Invalidate(); }
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        base.OnPaint(e);

        e.Graphics.DrawRectangle(Pens.Black, 0,0, Width-1, Height-1);

        var x1 = 50;
        var x2 = 98;
        var x3 = 146;
        var color1 = battery1Fail?_failColor:BackgroundTextColor;
        var color2 = battery2Fail?_failColor:BackgroundTextColor;
        var color3 = battery3Fail?_failColor:BackgroundTextColor;

        e.Graphics.FillRectangle(new SolidBrush(color1),x1+1, 1, 47, Height-2);
        e.Graphics.FillRectangle(new SolidBrush(color2),x2+1, 1, 47, Height-2);
        e.Graphics.FillRectangle(new SolidBrush(color3),x3+1, 1, 47, Height-2);

        e.Graphics.DrawLine(Pens.Black, x1,0, x1, Height-1);
        e.Graphics.DrawLine(Pens.Black, x2,0, x2, Height-1);
        e.Graphics.DrawLine(Pens.Black, x3,0, x3, Height-1);

        var BoldFont = new Font(this.Font, FontStyle.Bold);

        e.Graphics.DrawString(Caption, BoldFont, new SolidBrush(ForeColor), 0,0);
        e.Graphics.DrawString(Text, this.Font, new SolidBrush(ForeColor), x1,0);
        e.Graphics.DrawString(Text2, this.Font, new SolidBrush(ForeColor), x2,0);
        e.Graphics.DrawString(Text3, this.Font, new SolidBrush(ForeColor), x3,0);

    }   
}

控件大小应为 195,14,以防您决定尝试使用它。我在一个 200,200 的面板中有 8 个,在 1.6Ghz 原子处理器上运行。它用于在计算机上显示最多 3 节电池的值。标签每 500 毫秒刷新一次。正如您可能已经收集到的那样,有一点闪烁,但这是可以容忍的。如果可能的话,我希望更少。所以我开始研究使用更新,并移动我的一些代码,比如我想也许我应该把它移动到 OnPaintBackground() 的背景位,但是在我组成的测试框架中,更新方法并没有改变任何东西,并且当我使用 Invalidate 方法时,它同时运行 OnPaintBackground 和 OnPaint。这是我在这种情况下尝试的方法。

public class InformationLabel : Control
{
    Random r = new Random();
    protected override void OnPaintBackground(PaintEventArgs e)
    {
        base.OnPaintBackground(e);
        Color randomCOlor = Color.FromArgb(r.Next());
        e.Graphics.FillRectangle(new SolidBrush(randomCOlor),0,0, Width-1, Height-1);
    }
    protected override void OnPaint(PaintEventArgs e)
    {
        base.OnPaint(e);
        Color randomCOlor = Color.FromArgb(r.Next());
        e.Graphics.FillPie(new SolidBrush(randomCOlor),15,15,15,15, 0.0f, 120.0f);
    }
}

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

    void Button1Click(object sender, EventArgs e)
    {
        informationLabel1.Update();
    }

    void Button2Click(object sender, EventArgs e)
    {
        informationLabel1.Invalidate();
    }
}

我将一个用户控件设置为大约 300,300,这样我就可以确定我看到了什么。我忘了提到在我的 500 毫秒计时器的电池控制中,我只是更新文本、文本 2 和文本 3。我在想,如果该文本的值超出规范,我将设置电池故障标志,然后无效.. 但我不确定。那么我应该如何只更新文本???

【问题讨论】:

    标签: c# custom-controls flicker onpaint


    【解决方案1】:

    您可以通过在构造函数中添加此行来消除闪烁:

    SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.UserPaint | ControlStyles.Opaque | ControlStyles.AllPaintingInWmPaint, true);
    

    现在在您的绘制处理程序中绘制背景和其他所有内容。

    可以通过将 Rectangle 传递给 Invalidate 来仅针对需要重新绘制的区域进行优化。然后在您的 OnPaint 覆盖中,您使用 e.ClipRectangle 来确定要绘制的内容。对于这么简单的绘图,这可能不是必需的。

    【讨论】:

      【解决方案2】:

      我相信你在寻找错误的地方来消除闪烁。我可以使用您的BatteryLabel 基本上用一行来无闪烁更新文本。将您的构造函数更改为如下所示:

      public BatteryLabel()
      {
          this.SetStyle(ControlStyles.OptimizedDoubleBuffer,true);
      }
      

      这告诉控件双缓冲其图形,从而使闪烁消失。

      以 100 毫秒的刷新间隔进行测试:

      Timer t;
      public Form1()
      {
          InitializeComponent();
      
          t = new Timer();
          t.Interval = 100;
          t.Tick += new EventHandler(t_Tick);
          t.Start();
      }
      
      void t_Tick(object sender, EventArgs e)
      {
          string ticks = DateTime.Now.Ticks.ToString();
          string ticks1 = ticks.Substring(ticks.Length-4),
              ticks2 = ticks.Substring(ticks.Length - 5,4),
              ticks3 = ticks.Substring(ticks.Length - 6,4);
      
          batteryLabel1.Text = ticks1;
          batteryLabel1.Text2 = ticks2;
          batteryLabel1.Text3 = ticks3;
          batteryLabel1.Battery1Fail = ticks1.StartsWith("1");
          batteryLabel1.Battery2Fail = ticks2.StartsWith("1");
          batteryLabel1.Battery3Fail = ticks3.StartsWith("1");
      }
      

      这有帮助吗,还是我误解了你?

      【讨论】:

      • 下面的 @Tergiver 给出了基本相同的解决方案,但添加了几个额外的标志,这些标志可能会提高操作的效率。不错的主意,因为您实际上是在做自己的绘画。你会发现,如果你只用最小的 ControlStyles.OptimizedDoubleBuffer 尝试它,它甚至可以在比你实际使用的刷新率高得多的情况下工作,但没有理由不设置其他标志。
      • 好吧,我现在有家人,所以我无法测试它。但是当我这样做时,我会告诉你。不过这看起来很有希望。
      猜你喜欢
      • 1970-01-01
      • 2016-01-01
      • 2017-01-02
      • 2013-10-23
      • 2011-04-15
      • 1970-01-01
      • 1970-01-01
      • 2020-02-24
      • 2011-02-10
      相关资源
      最近更新 更多