调整窗口大小会导致黑色条纹

3

我有一个表单,在构造函数中设置了以下样式:

this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
this.SetStyle(ControlStyles.UserPaint, true);
this.SetStyle(ControlStyles.ResizeRedraw, true);
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);

我在Paint事件中绘制了一些矩形。表单上没有控件。然而,当我调整窗体大小时,窗体右侧和底部会出现黑色条纹。有没有办法摆脱它们?我已经尝试过所有方法,包括在WndProc中监听WM_ERASEBKGND,手动在WM_PAINT中绘制窗体,实现自定义双缓冲等。还有其他什么方法可以尝试吗?

我找到了这个链接:https://connect.microsoft.com/VisualStudio/feedback/details/522441/custom-resizing-of-system-windows-window-flickers,看起来像是DWM的一个bug,但我希望能够找到一些解决方法。

请注意,我必须使用双缓冲,因为我想在Paint事件中绘制相当复杂的图形展示。我使用C# .NET 2.0,在Win7上进行开发。

状态更新1

我通过自己实现调整大小功能成功地摆脱了大部分黑色条纹。然而,仍然存在一些小故障。有没有办法同时进行resizepaint操作?这是我需要做的伪代码

IntPtr hDC;
var size = new Size(250, 200);
IntPtr handle = API.PaintAndResizeBegin(this.Handle /* Form.Handle */,
                                        size.Width, size.Height, out hDC);
using (var g = Graphics.FromHdc(hDC)) {
    this.backBuffer.Render(g, size);
}
API.PaintAndResizeCommit(handle);

有没有办法实现上述代码?

第二种解决方案是将整个表单(包括非客户端区域)进行后备缓冲。但是如何做到这一点呢?我不想自己绘制非客户端区域,因为我想保持Vista/7上的漂亮的aero效果。任何帮助将不胜感激。

状态更新2

看起来这个问题无法解决,因为它在Windows中无处不在,在每个应用程序中都存在。我们只能希望微软从Mac OS X中汲取灵感,在新的Windows中提供适当的API。

2个回答

1

我找到了一个可以同时绘制和调整窗口大小的函数 - UpdateLayeredWindow

现在应该可以创建可调整大小的窗口,而在调整大小时不会有任何条纹。但是,您需要自己绘制窗口内容,因此有点不方便。但我认为使用WPFUpdateLayeredWindow,就不应该有任何问题。


更新

发现问题。:-) 当使用UpdateLayeredWindow时,您必须自己绘制窗口的边框。因此,如果您想要在win7中使用UpdateLayeredWindow绘制标准窗口并具有漂亮的玻璃效果,则会遇到困难。

Microsft Connect上甚至有一个关于这个问题的线程,微软表示这是一个设计缺陷,如果它被修复,那么可能会在Win8或某个更新的系统中进行修复。所以我们对此无能为力。


0

我发现最好不要直接在表单表面进行任何自定义渲染。相反,在表单上放置一个停靠的PictureBox,创建将显示在PictureBox中的Bitmap对象,使用System.Drawing.Graphics.FromImage(Image)方法将所有内容绘制到其中。

我使用该方法与游戏循环制作了一个简单的射击游戏(Crimsonland风格),并获得了相当不错的性能(带有抗锯齿线条),超过100 FPS。


那么,您可以在Resize上执行重建,而不是ResizeEnd,但这会有点慢,不如您所希望的那样平滑。对于这种性能,您不能使用GDI来进行繁重的工作(即使用Graphics或Bitmap类)。相反,使用硬件加速API(这就是MacOS和Vista/7用于平滑一切的方法)。对于.NET,请查看WPF(甚至XNA)。您可以通过它们获得完美流畅的渲染,并且您将获得0行代码的调整大小。 - Allon Guralnek
没错,没有人阻止微软添加新的API,这些API不会有这样的问题。因此,新的应用程序可以使用该API并且不会出现任何故障,而旧的应用程序将像以前一样运行。顺便说一句,API并没有被弃用。例如,DwmExtendFrameIntoClientArea可以将玻璃扩展到客户区域,只能作为API使用。 - Paya
真实,这正是他们正在做的事情 - 添加更新、更好的API。但这并不阻止人们继续使用旧的API,这就是为什么你仍然会看到故障和性能差的原因。当然,API作为一个概念并没有被弃用(它不能被弃用,这是应用程序之间唯一的通信方式),我所说的是某些API已经被弃用,并被新的API所取代。当新版本的MacOS出现时,所有旧的东西都被删除了,应用程序就会崩溃,但苹果的用户和开发者已经习惯了这种情况 - 对于更好的(没有负担)和更糟糕的(崩溃),对于Windows也是如此。 - Allon Guralnek
编辑:不是自从第一个Win版本,而是自从第一个具有实时更新调整大小功能的Win版本。 - Paya
就像我之前说的那样,我相信一个WPF应用程序不会有这些问题,但我可能是错的。 - Allon Guralnek
显示剩余12条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接