在 绘图 或 绘 制控件 过 程中最 让 人郁 闷 的便是 复杂绘 制的 闪烁问题 。 如果您 为该问题 所困 扰 ,那 么 您 应该 注意以下几点:
1 , 使用 缓 冲:
比如要向 Graphics 对 象 g 上 绘 制 图 形, 你可以在内存中使用一 张图 片作 为缓 冲,先将 图 形 绘 制到 该图 片上, 绘 制完成后再将 该图 片 绘 制到 g 上。
Bitmap buffer = new Bitmap( this . Width , this . Height);
using (Graphics bufferGrfx = Graphics . FromImage(buffer))
{
// 绘 制到bufferGrfx 上
}
// 把缓冲图片绘制到 g 上
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
运用剪 辑 区域, 这 很重要 , 很 简单 地,比如 图 形区域只有很小一个部分需要更新你就没有必要更新全部 图 形区域。
具体 说 来就是,只有那些和剪 辑 区域相交 ( 或被剪 辑 区域包含 ) 的区域才需要 绘 制。
注意这里是e.ClipRectangle而不是g.Clip,g.Clip表示的是该画布的绘图区域,其和e.ClipRectangle(本次描画的剪辑区域)没有本质联系。
// 假 设 Block 对 象是程序的最小 绘 制 单 元
foreach (Block bk in this . Blocks)
{
if ( 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 点不是白 说 了 )