2012-06-08 34 views
0

由于篇幅较短且易于理解,我将首先发布我的代码,然后我会问我的问题。如何在自定义控件中使用Control.Update方法

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。我有8个这样的面板,它是在一个1.6Ghz原子处理器上运行的200,200。它用于显示计算机上最多3个电池的数值。标签每500ms刷新一次。正如你可能聚集的那样,有一点点闪烁,但它是可以忍受的。如果可能,我只想更少。所以我开始研究使用Update,并移动我的一些代码(比如背景位),我想也许我应该将它移动到OnPaintBackground(),但是在构建Update方法的测试框架中不会更改任何内容,并且当我使用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(); 
    } 
} 

我做了一个usercontrol约300,300,所以我可以肯定我所看到的。我忘了提及在我的500毫秒计时器的电池控制中,我只是更新文本,text2和text3。我在想,如果该文本的价值超出规格,我会设置电池失效标志,然后无效..但我不知道。那么我应该如何去更新文本?

回答

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

这是否帮助,或者有我误解你了?

+0

@Tergiver下面给出了基本相同的解决方案,但增加了一些可能会提高操作效率的附加标志。不是一个坏主意,因为你实际上在做你自己的绘画。你会发现,如果你只用最小的ControlStyles.OptimizedDoubleBuffer来尝试它,即使刷新率比你实际使用的刷新率高得多,但是没有理由不设置其他标志。 –

+0

好吧,我现在有家庭,所以我无法测试它。但是当我这样做,我会让你知道。这看起来很有希望。 –

3

您可以通过添加在你的构造这条线摆脱闪烁:

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

现在,油漆背景和在您的油漆处理一切。

优化可以通过只为需要重新绘制的区域传递一个Rectangle来使Invalidate完成。然后在你的OnPaint覆盖中,使用e.ClipRectangle来确定要绘制的内容。对于这样简单的绘图来说,这可能不是必需的。

相关问题