提示:Refresh, Update, 和 Invalidate的区别

最近,一些人问我,为什么要用Invalidate代替Refresh用来使控件重画。Invalidate和Refresh这两种方法都会使控件的绘制事件的处理程序执行,所以,为什么非要挑选一个呢?

从我的目的来说,我认为你用哪一个并不重要。这是一篇有趣的帖子,解释Refresh, Update, 和 Invalidate之间的不同之处。

我是这么理解的:

1、Invalidate将窗口标记为无效,以便下次处理事件时重新绘制。也就是说Invalidate不是同步的。

2、如果控件的更新区域不是空的,则Update会向控件发送WM_PAINT消息。

3、Refresh调用Invalidate和Update以同步刷新。

所以,什么时候用这个,什么时候用那个呢?

好,让form做事的“一般”方式是将消息加入到消息队列中,并让它在可能的时候访问它们。这就是Invalidate所做的工作。(注:Invalidate只是放一个WM_PAINT消息在队列里,不做别的,所以只有当当前函数返回后,进入消息循环,取出WM_PAINT,才执行PAINT,所以不管Invalidate放哪里,都是最后的。)

Refresh会强制窗口处理无序的消息。理论上,我认为这可能会导致不必要的重绘。通常情况下,窗口的无效区域会被累加起来,当有时间时窗口会立即重绘所有无效区域。Refresh会强制各个无效区域分别进行重绘。

在实践中,我怀疑这对大多数项目来说都是一个问题。

我认为差异重要性的唯一合理的解释是,如果你正在做一件需要进行大量计算的事情,即使程序占用了太多CPU以至于消息队列没有取得多大进展,你也想要立刻强制重绘。在这种情况下,你可能需要使用Refresh。

所以你一直在用使用Refresh嘛?或许是的。看起来由此导致出问题的情况是比较少见的。

有一个重要的补充:

我认为的情况是:我想Invalidate才是正确的选择。

有时候,GDI+需要相当长的时间来绘制你希望它要绘制的内容。比如说,你可能会在一个图像框内叠加了很多个部分透明的图像层,或者说你正在用DrawString or GraphicsPath.Addstring画一个形状复杂的图形。你也可以用PathGradientBrush做一些艺术着色,尤其是这几种内容的结合。

只要图片不变化,一切都还好说。但是,假设你正在用鼠标拖动图像的一个组件,如果在每次鼠标移动过程中都要强制Refresh图片框,由于MouseMove事件的触发速度比GDI+在新位置绘制的速度快,因此效果可能会顿挫而缓慢。

如果你制作一个动画,并且在每一个Timer.Tick上使用Refresh,受影响的效果也会显现出来。绘制图像所需的时间可能长于计时器间隔,因此其效果将降低帧速率。在这种情况下,哪个更好取决于动画的角色。经过动态变形的图像最好进行刷新(即使刷新速度较慢),因为跳过中间帧看起来很糟糕。但是在屏幕上移动的精灵最好使用Invalidate,因为这样可以不破坏运动错觉的情况下允许跳过不必要的帧。

Invalidate可以用于指定要刷新的矩形。使用鼠标拖动子图像时,只需使以前的边界和新边界无效,而不必使整个控件无效。对于计时动画也是如此。当像素绘制时间很紧时,这可能是获得平滑动画的一个重要因素。总而言之,我认为提醒人们在Refresh和Invalidate之间有一个真正的选择是很有用的,之后可能是Update。在性能是一个问题的情况下,可能需要一个接一个地尝试,看看哪一个能带来最好的结果。这种比较还取决于图形硬件,所以一个严肃的图形程序员在选择方法时必须考虑到这一点。

 

posted @ 2022-05-10 23:04  chenlight  阅读(701)  评论(0编辑  收藏  举报