具有 GDI 的图层+
我正在考虑创建一个带有图层的绘图程序,并使用 GDI+ 来显示它们。我想使用 GDI+,因为它支持透明度。
问题是,在 DC 上绘制线条非常快,但直接在位图上绘制则非常慢。只有当您锁定位并开始设置像素时,它才会很快。我可以在 WM_PAINT 事件中绘制到多个 DC,然后只对 MemDC 的每个图层执行 DrawBitmap 吗?解决这个问题的最佳方法是什么?
谢谢
I'm thinking of creating a drawing program with layers, and using GDI+ to display them. I want to use GDI+ because it supports transparency.
The thing is, drawing lines to the DC is very fast, but drawing directly to a bitmap is very slow. It is only fast if you lock the bits and start setting pixels. Can I draw to multiple DC's in my WM_PAINT event, then just do DrawBitmap for each layer to the MemDC? What's the best way of going about this?
Thanks
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
对于绘图程序来说,GDI+ 确实足够快。我使用它(来自 C#)来实现高速动画(> 30 fps)。
看来您希望能够操纵单个像素。使用 LockBits 速度非常,虽然在 C# 中使用它有点笨拙(需要指针和
unsafe
标记),但看起来并不像那样在C++中很难。您可能不想在绘画事件中直接从多个图层复制到控制表面。相反,此渲染应该在离屏缓冲区 (B1) 上完成。在完成所有复制/绘制操作后绘制 B1 后,将其复制到第二个离屏缓冲区 (B2),然后使控制表面无效/刷新。在控件的绘制事件中,您从 B2 复制到可见表面。
您不想通过多步绘制操作直接在可见表面上绘制,因为会导致某种形式的闪烁(有时,当您的代码仅完成多步操作的一半时,屏幕会重新绘制自身,因此用户偶尔会看到半成品的框架)。
您可以渲染到单个离屏缓冲区,然后将其复制到绘制事件中的可见表面。这里的主要复杂性是,您必须以某种方式处理“杂散”绘制事件,即不是由您故意使控件无效而是由其他原因引起的事件(例如用户将另一个窗口拖到您的窗口上)。如果您从屏幕外缓冲区复制到表面,并且缓冲区仅绘制到一半,则会出现闪烁。如果您阻止绘制事件直到缓冲区绘制完成,您将在控件上看到“表单轨迹”,这看起来更糟。
解决方案是上面描述的双缓冲方法。杂散(或无效时的非杂散)绘制事件将从 B2 复制,B2 始终完全渲染且最新 - 因此不会闪烁。双缓冲确实会使用更多内存,但在具有多层的绘图程序中,这并不是什么大问题。
GDI+ is certainly fast enough for a drawing program. I use it (from C#) for high-speed animation (>30 fps).
It appears that you want to be able to manipulate individual pixels. This is very fast with LockBits, and although it's slightly clunky to use in C# (requiring a pointer and the
unsafe
tag), it doesn't seem like it would be as difficult in C++.You probably don't want to copy from multiple layers directly to your control surface inside a paint event. Instead, this rendering should be done to an off-screen buffer (B1). After B1 is drawn with all copying/drawing operations completed, copy it to a second off-screen buffer (B2) and then invalidate/refresh your control surface. In the control's paint event, you copy from B2 to the visible surface.
You don't want to draw directly on the visible surface with a multi-step drawing operation, since a form of flickering will result (sometimes the screen will repaint itself while your code is only partway through a multi-step operation, so the user sees an occasional half-finished frame).
You can render to a single off-screen buffer, and copy from it to the visible surface in the paint event. The main complication here is that you have to deal in some way with "stray" paint events, i.e. events not caused by your intentionally invalidating the control but by something else (like a user dragging another window over yours). If you copy from the off-screen buffer to the surface and the buffer is only halfway-drawn, you'll get flicker. If you block in the paint event until the buffer drawing is completed, you'll see "form trails" on your control, which looks even worse.
The solution is the double-buffered approach described above. Stray (or non-stray ones when you invalidate) paint events will copy from B2, which is always fully-rendered and up-to-date - thus no flicker. Double-buffering does use more memory, but in a drawing program that has multiple layers anyway, this isn't a big deal.