使用 gdi+ 进行无闪烁绘图

Posted

技术标签:

【中文标题】使用 gdi+ 进行无闪烁绘图【英文标题】:Flickerfree drawing using gdi+ 【发布时间】:2015-10-06 17:28:37 【问题描述】:

我有一个要绘制的 .png 文件,但问题是,我每 1/10 秒绘制一次该 png,因此每秒绘制 10 次。这个 png 是以 X 和 Y 坐标为中点绘制的,所以图像的中间是 X 和 Y 坐标。

使用此代码:

private void frmMap_Paint(object sender, PaintEventArgs e)

   Bitmap FlashLight = new Bitmap(
      Image.FromFile(AppDomain.CurrentDomain.BaseDirectory + @"light.png"), 4000, 2160);
   e.Graphics.DrawImage(FlashLight, new Point(mapX, mapY));

但问题是,当每秒绘制 10 次此 png 时,随着 X 和 Y 坐标的变化会导致大量闪烁。

有人知道如何减少或消除闪烁吗?我已经研究过在屏幕上绘制位图并在绘制完成后加载它,我不知道如何做到这一点。

我还研究了双缓冲,但我也不知道如何使用它来减少闪烁。

【问题讨论】:

看起来您正在表格上绘画。它有一个属性DoubleBuffered,这是第一步。但不要抱太大希望;使用 Winforms 制作动画是相当有限的.. 另外,您在每次绘制迭代时都重新加载位图。这真是太浪费了。只做一次。 @TaW 你会推荐使用什么来制作这个动画?因为我只是在新位置重绘 png,但重绘的问题是屏幕变白,整个 png 被重绘。它不必是流畅的动画,它可以是粗壮的,但不要闪烁太多 您可以移动显示图像的(最佳缓冲)控件,而不是进行任何绘图。看我的回答! 【参考方案1】:

Winforms 绝对不适合动画。

这里有一个建议,你可能觉得不够好:

将大的Image 加载到PictureBox.Image 并设置PictureBox.SizeMode = AutoSize

然后在您的动画Timer.Tick 中移动PictureBox

这是一个小例子:

Timer timer = new Timer();
timer.Interval = 100;
timer.Tick += timer_Tick;

// when the timer runs..
timer.Enabled = !timer.Enabled;

..它移动PictureBox

void timer_Tick(object sender, EventArgs e)

    Point pt = new Point(pictureBox1.Left + offsetX, pictureBox1.Top + offsetY);
    pictureBox1.Location = pt;

注意,位置可以毫无问题地进入负片!

要将图像的初始位置居中使用:

pictureBox1.Location = new Point(-(pictureBox1.Width - Width)/2, 
                                 -(pictureBox1.Height - Height)/2);

要获得更好的动画支持,您可以考虑使用 WPF。

【讨论】:

我对这些东西 atm 很陌生,所以这个问题听起来可能很愚蠢,但是 offsetX 和 offsetY 是什么意思 因为我知道你在做什么,但我需要提供(已知)需要作为图片框起点的 X 和 Y 坐标正在移动,甚至更好的是图片框的中间点 你想移动图像,对吧?所以你需要改变它的位置。这就是这两个变量的用途。要使初始位置居中,您将像这样计算 pb.left= -(pb.width - form.width) / 2;等等。 好。正如我写的那样,这应该比您的原始代码要好得多,但是要获得真正流畅的运动,您必须学习 WPF。 你看到我每秒只能获得 10 个 x,y 坐标,无论如何它不能平滑,

以上是关于使用 gdi+ 进行无闪烁绘图的主要内容,如果未能解决你的问题,请参考以下文章

win32-gdi系统驱动的WM_PAINT无闪烁吗?

离屏绘图 GDI+

在 Qt 中通过 Windows GDI 绘图

GDI+ 闪烁

VC++大数据量绘图时无闪烁刷屏技术实现(我的理解是,在内存上作画,然后手动显示,而不再直接需要经过WM_PAINT来处理了)

Java AWT 图形界面编程Canvas 组件中使用 Graphics 绘图 ④ ( AWT 绘图窗口闪烁问题 )