如何在画布上快速重绘.C#WINFORM

本文关键字:C#WINFORM | 更新日期: 2023-09-27 18:26:19

对于我的软件,我使用Systems.Timer库中的Timer,每次我的计时器滴答作响时,它都会调用一个重新绘制屏幕的方法。我不想清除屏幕,然后在上面重新绘制。我只想直接在上面绘制新的区域。

一开始,我这样做:

Constructor{
   ...
   this.timer = new Timer
   {
      Interval = 10,
   };
   this.timer.Elapsed += OnPaint;
   this.timer.start();
}
public void OnPaint(Object sender, EventArgs e)
{
   This.Parent.OnPaintLoadingCircle();
   This.Parent.OnPaintReadyToBePaintedAreas();
}

然后我注意到,当OnPaint方法包含以下内容时,绘制速度要快得多:

public void OnPaint(Object sender, EventArgs e)
{
   This.Parent.Invalidate();
}

所以我有两个问题:

问题1:

为什么它更快???

因为当我调用invalidate()时:

  • UI线程清除屏幕
  • 然后UI线程重新绘制旧区域
  • 然后UI线程绘制加载圆
  • 然后UI线程绘制新的区域

当我调用我的两个方法OnPaintLoadingCircle()和OnPaintReadyToBePaintedArea()时:

  • 计时器线程绘制加载圆
  • 然后计时器线程绘制新区域

问题2:

我想知道是否有一种方法可以让控制器在不清除它的情况下绘制它的曲面。Parent.Refresh(),两者都首先清除屏幕)。

非常感谢您的帮助。

如何在画布上快速重绘.C#WINFORM

为什么它更快???

原因最简单:因为当您在OnPaint()方法中调用Invalidate()时,它会强制立即重新绘制窗口,这比计时器要快得多。

.NET中的计时器不适用于高频操作。它们只保证间隔之间的时间至少是您指定的。实际间隔可以而且通常比您指定的间隔长,尤其是如果您使用的间隔非常短(例如,小于10-20ms)。这必然会限制在使用计时器时重新绘制窗口的频率,这比尽可能快地重新绘制窗口要大得多。

我想知道是否有一种方法可以让控制器在不清除的情况下将其绘制出来

不容易。在最基本的级别上,您可以覆盖OnPaintBackground()而不调用基本实现。但只有当你准备重新绘制所有内容时,这种方法才有效,因为系统指望你在绘制时用正确的像素来掩盖过时的像素。

事实上,更常见的方法是使用双缓冲。最基本的形式是只在控件构造函数中设置DoubleBuffered属性。但您也可以将不清除窗口与维护自己的屏幕外Bitmap对象结合起来,将内容绘制到该对象中。然后,当Paint事件发生时,只需将Bitmap复制到窗口即可。

一种更复杂的方法涉及在窗口中托管Direct2D曲面。不适合胆小的人,但应该在Winforms节目中提供尽可能好的表演。