【问题标题】:Resizing window causes black strips调整窗口大小会导致黑条
【发布时间】:2010-04-10 13:00:59
【问题描述】:

我有一个表单,它在构造函数中设置这些样式:

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 中的一个错误,但我只是希望我能做一些解决方法。

请注意,我必须使用双缓冲,因为我想在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 上保持良好的航空效果。任何帮助将不胜感激。

状态更新 2

看起来这个问题是无法解决的,因为它在 Windows 上无处不在,在每个应用程序中。我们只能希望 MS 在 Mac OS X 中获得一些灵感,并在新的 Windows 中提供适当的 API。

【问题讨论】:

    标签: c# .net windows windows-7 flicker


    【解决方案1】:

    我找到了可以同时绘制和调整窗口大小的功能 - UpdateLayeredWindow

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


    更新

    发现问题。 :-) 使用UpdateLayeredWindow 时,您必须自己绘制窗口的边框。所以,如果你想在 win7 中使用 UpdateLayeredWindow 绘制具有漂亮玻璃效果的标准窗口,那你就完蛋了。

    Microsft Connect 甚至是一个关于这个问题的线程,微软说这是一个设计上的错误,如果它得到修复,那么可能在 Win8 或一些更新的系统中。所以我们对此无能为力。

    【讨论】:

      【解决方案2】:

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

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

      【讨论】:

      • 当你调整窗口大小时黑色条纹消失了?如果我只创建一个空白表单,则调整大小是可以的,没有黑色条纹。但是,如果我在 OnPaint 中添加一些控件或进行一些不太快的绘画,如果您拖动表单的角并尽可能快地调整它的大小,则会出现黑色条纹。看起来这些条纹是由系统而不是我的应用程序绘制的,因为几乎每个应用程序都有这个“功能”。如果没有黑色条纹,则在调整大小期间,控件仅超出窗体的左/下角几分之一秒。
      • 使用PictureBoxBitmap方法时,不需要设置任何ControlStyles。创建您绘制的位图时,您必须指定一个固定大小。如果用户调整了窗口大小,您必须使用窗口的新大小重新创建位图。展开表单(或您设置BackColorForm 的任何颜色)将填充灰色,直到您释放鼠标,然后触发ResizeEnd 事件,您必须在其中重新创建位图。在任何情况下,都没有黑条(除非您将表单的 BackColor 设置为黑色)。
      • 这些条形图的颜色与BackColor 相同,但这并不重要。有酒吧!如果它们是灰色或黑色无关紧要。我只想流畅地调整大小而不会出现任何图形故障,就像在 Mac OS X 上一样。只需尝试在 Mac OS X 和 Windows 7 上快速调整某些窗口的大小,您就会明白我的意思。
      • 那么您可以在Resize 而不是ResizeEnd 上执行娱乐,但这会有点慢并且不像您想要的那么顺利。对于这种性能,您不能使用 GDI 进行繁重的工作(即使用 Graphics 或 Bitmap 类)。相反,使用硬件加速 API(这是 MacOS 和 Vista/7 用于平滑一切的工具)。对于 .NET,看看 WPF(甚至是 XNA)。您可以使用它们获得黄油般平滑的渲染,并且只需 0 行代码即可调整大小。
      • 嗯,VS2010 是用 WPF 编写的,它也有完全相同的 black-strip-on-resize 问题。只需打开VS2010,不要打开任何项目,将属性窗口停靠在左侧并尝试大幅调整窗口大小。但你可能是对的,GDI 只是不够快。所以使用 WPF 和我自己的调整大小实现可以解决这个问题。
      猜你喜欢
      • 2020-02-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-13
      • 2019-06-17
      相关资源
      最近更新 更多