【发布时间】:2013-01-12 03:31:33
【问题描述】:
我正在尝试将一个小图像从左侧移动到屏幕右侧。
我将用户控件的样式设置为:
this.SetStyle(ControlStyles.Opaque, true);
this.SetStyle(ControlStyles.UserPaint, true);
this.SetStyle(ControlStyles.ResizeRedraw, true);
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
在我的 OnPaint 处理程序中,我将对象绘制到 BufferedGraphics 实例,这是我的屏幕外缓冲区,然后使用单个调用将结果 BitBlt 到 e.Graphics 引用。
所以我似乎按照书本做了所有事情,以获得超流畅的无闪烁绘图,但我仍然可以看到对象有点口吃。
因此,基本上剩下两种可能性:调用.Invalidate(DirtyRect) 的计时器没有以恒定的时间间隔精确触发,导致对象出现卡顿,或者 BitBlt 没有按预期工作。
有人知道可能是什么问题吗?
更新:再想一想,它看起来更像是撕裂,而不是口吃或闪烁。因为有时对象似乎错过了最后几个像素。我将研究利用 VSYNC 的可能性。
【问题讨论】:
-
您看到卡顿或闪烁了吗?此外,查看重现代码会很有用...
-
@usr 这很难说。目前它只是一条穿过屏幕的红线,我可以看到它并不完全平滑。我猜它在撕裂,因为这条线是 2 像素宽,而在那些时刻,它似乎只有 1 像素宽。我做了一些研究,没有办法在 WinForms 中利用 VSYNC,所以我想我不走运。
-
在 TFT 显示器上移动的红线可能由于 TFT 或眼睛的延迟而变得模糊。这与你的观察一致吗?尝试捕获屏幕截图以确认该线实际上是 2px 宽一会儿。
-
@usr 我已经尝试截取问题的屏幕截图,但它从未出现,但可能是 Windows 在合适的时刻(垂直同步之间)捕获屏幕截图。此外,问题不在于线条看起来更宽(会变得模糊),而是看起来更细。
-
你用什么定时器? (默认的 Timer 类对于平滑动画来说不够准确 - GDI+ 也不适合这个问题)。 GDI+ 不允许您通过 vsync(或 vblank)进行同步,因此您需要为此设置低级别。 Invalidates 最终会在可能时呈现的队列中结束。您可以使用 Refresh (invalidate + Update) 强制更新
标签: .net gdi+ gdi flicker double-buffering