其中一個技巧是如何讓畫面重繪時不閃爍,除了裡面提到的方法外,我也在網路上參考了其他資料,並做個整理。
重繪畫面會閃爍的原因,是因為畫面更新時,程式會先將畫面清空,再將新的畫面畫上去。
因此清空的那一瞬間,就會產生閃爍的感覺。
解決的方式:
照 MSDN 的文件說明,使用「雙重緩衝圖形」即可。
也就是畫面重繪時,不直接在螢幕上重繪,而是先在緩衝區重繪,等整個畫面都重繪完成,才一次放到螢幕上。
使用雙緩衝繪圖的方法,目前我找到的方式有以下幾種
- 將 DoubleBuffered 屬性設為 true。
可在視窗屬性面版將 DoubleBuffered 設為 true,
或在程式碼中設定。此為 MSDN 上的方法public Form1() { InitializeComponent(); this.DoubleBuffered = true; }
- 設定 ControlStyles.AllPaintingInWmPaint、ControlStyles.OptimizedDoubleBuffer 為true,此為 MSDN 上的方法,MSDN 只提到 ControlStyles.OptimizedDoubleBuffer,但我在 VS 2012 測試時, VS 2012 提示還要設定 ControlStyles.AllPaintingInWmPaint
public Form1() { InitializeComponent(); this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer, true); }
- 設定 ControlStyles.UserPaint、ControlStyles.AllPaintingInWmPaint、ControlStyles.DoubleBuffer 為true,此為 MSDN上的方法
public Form1() { InitializeComponent(); this.SetStyle( ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint | ControlStyles.DoubleBuffer, true); this.UpdateStyles();//這行我測試沒設定似乎也可以,但MSDN上有此行 }
- 使用 BufferedGraphicsContext 手動管理雙緩衝,此為 MSDN上的方法
namespace WindowsFormsBufferedGraphics { public partial class Form1 : Form { private float x=0; private float y=0; public Form1() { InitializeComponent(); this.timer1.Enabled = true; this.timer1.Interval = 50; } private void timer1_Tick(object sender, EventArgs e) { this.x += 1; BufferedGraphicsContext currentContext = BufferedGraphicsManager.Current; BufferedGraphics myBuffer = currentContext.Allocate(this.CreateGraphics(), this.DisplayRectangle); //清除繪圖畫面,並用原本的背景色填充,否則呈現黑色背景 myBuffer.Graphics.Clear(this.BackColor); myBuffer.Graphics.DrawEllipse(Pens.Blue, this.x, this.y, 50, 50); myBuffer.Render(this.CreateGraphics()); myBuffer.Dispose(); } } }
- 另一個手動管理雙緩衝,我在 Gary Lin 的 C# 遊戲程式設計 學到的方法
namespace WindowsFormsBufferedGraphics2 { public partial class Form1 : Form { private float x = 0; private float y = 0; private Graphics backGraphics; private Bitmap backBmp; public Form1() { InitializeComponent(); this.backBmp = new Bitmap(this.DisplayRectangle.Width, this.DisplayRectangle.Height); this.backGraphics = Graphics.FromImage(backBmp); this.timer1.Enabled = true; this.timer1.Interval = 50; } private void timer1_Tick(object sender, EventArgs e) { this.x += 1; //重新填充背景色,否則會殘留之前的圖形 this.backGraphics.FillRectangle(Brushes.White, 0, 0, this.DisplayRectangle.Width, this.DisplayRectangle.Height); this.backGraphics.DrawEllipse(Pens.Blue, this.x, this.y, 50, 50); this.CreateGraphics().DrawImageUnscaled(this.backBmp, 0, 0); } } }
參考資料:
沒有留言:
張貼留言