绘制,不再闪烁

                         绘制, 不再闪烁
   
                                        电子科技大学软件学院 03级02班 周银辉

    在绘图或绘制控件过程中最让人郁闷的便是复杂绘制的闪烁问题. 如果您为该问题所困扰,那么您应该注意以下几点:

1, 使用缓冲:
    比如要向Graphics 对象 g 上绘制图形, 你可以在内存中使用一张图片作为缓冲,先将图形绘制到该图片上,绘制完成后再将该图片绘制到g上.
   
Bitmap buffer = new Bitmap(this.Width, this.Height);

using (Graphics bufferGrfx = Graphics.FromImage(buffer))
{
    
//绘制到bufferGrfx上
}



Rectangle srcRect 
= this.bounds;
Rectangle destRect 
= srcRect;

g.DrawImage(buffer, destRect, srcRect, GraphicsUnit.Pixel);


  不用担心两次绘制会带来效率上的损失, 其速度与直接绘制到g上几乎一样快.

2, base.OnPaint(e);
    如果所有的绘制操作都由自己来完成,那么在覆盖OnPaint方法时, 请 不要 使用base.OnPaint(e);

3, e.ClipRectangle
    运用剪辑区域, 这很重要, 很简单地,比如图形区域只有很小一个部分需要更新你就没有必要更新全部图形区域.
    具体说来就是,只有那些和剪辑区域相交(或被剪辑区域包含)的区域才需要绘制.


//假设Block对象是程序的最小绘制单元
foreach(Block bk in this.Blocks)
{
    
if (e.ClipRectangle.Contains(bk.Bounds) ||
     e.ClipRectangle.IntersectsWith(bk.Bounds))
    
{
        
//draw bk;
    }

}

4, Refrush(), Invalidate(), Update()
    不要轻易使用Refrush来刷新图形.
    在刷新之前,请先确定要刷新的区域,如果要刷新的区域只是图形区域的一部分,您应该使用Invalidate()来使该区域无效,然后使用Update来更新这个无效区域便可.

5, SetStyle();
    其实在以上几点之前, 应该在控件的构造器(或其他初始化方法)中设置控件样式:
  
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
            
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            
这里的ControlStyles有好几个枚举,具体设置那些值,以及它们之间的相互关系,请参考MSDN说明文档.

6, DoubleBuffered
   有好几种标准控件是内置双缓冲的,比如Form,  PictureBox等, 您可以将它们的DoubleBuffered设置为true.来减少闪烁. (当然不要寄希望于仅仅设置该属性便万事大吉了, 不然以上5点不是白说了 : )


-----------------------------------
以上几点仅仅是编程过程中的经验总结,   若还有其他方法请补充  (肯定是有的).
原文地址:https://www.cnblogs.com/zhouyinhui/p/583225.html