使用 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+ 进行无闪烁绘图的主要内容,如果未能解决你的问题,请参考以下文章
VC++大数据量绘图时无闪烁刷屏技术实现(我的理解是,在内存上作画,然后手动显示,而不再直接需要经过WM_PAINT来处理了)