要通过双缓冲区减少闪烁:设置样式与重写CreateParam

本文关键字:样式 设置 重写 CreateParam 闪烁 双缓冲区 | 更新日期: 2023-09-27 18:22:08

有人能解释之间的区别和关系吗

SetStyle(ControlStyles.UserPaint |
         ControlStyles.AllPaintingInWmPaint |
         ControlStyles.DoubleBuffer, true)

protected override CreateParams CreateParams
{
    get
    {
        CreateParams cp = base.CreateParams;
        cp.ExStyle |= 0x02000000;  // Turn on WS_EX_COMPOSITED
        return cp;
    }
}

它们被要求减少闪烁,但何时以及如何正确使用它们?它们可以单独使用,也可以成对使用,原因是什么?

谢谢!

积分

第一个代码片段引用自MSDN页面;第二个代码片段是在"如何修复用户控件中的闪烁"上找到的,原作者是@HansPassant。

要通过双缓冲区减少闪烁:设置样式与重写CreateParam

感谢@terrybozzlo的解释和@Caramiriel的精彩页面澄清了问题。

我想总结一下我在这里得到的一切。


为什么我们有闪烁

当窗体或容器控件(如Panel)包含过多控件时(默认情况下为WS_CLIPCHILDREN打开时),通常会出现闪烁。根据@HansPassant:

它绘制BackgroundImage,在子控件窗口所在的位置留下洞。然后,每个子控件都会得到一条消息来绘制自己,它们会用窗口内容填充洞。当你有很多控件时,这些洞会在一段时间内对用户可见。它们通常是白色的,在黑暗时与背景图像形成强烈对比。或者,如果窗体设置了"不透明度"(Opacity)或"透明度关键帧"(TransparencyKey)属性,则它们可以是黑色的,与几乎任何东西都形成了严重的对比。

如何在控制级别避免它们

您应该将控件的DoubleBuffered属性设置为true。要做到这一点,您需要从基本类型派生控件(如果它不是用户控件),并在构造函数中设置它。

例如,要获得Panel双缓冲,您需要执行以下操作:

public class BufferedPanel : Panel
{
    public BufferedPanel()
    {
        DoubleBuffered = true;
    }
}

或者,您可以使用:

SetStyle(ControlStyles.UserPaint |
         ControlStyles.AllPaintingInWmPaint |
         ControlStyles.DoubleBuffer, true);

以获得相同的效果,即它们是等效的

如何在表单级别避免它们

上面的技术将减少控件级别的闪烁,这意味着当表单被重新绘制时,所有控件都不会再闪烁了。但最终的解决方案是从窗体级别减少闪烁:当窗体被重新绘制时,窗体及其所有子窗体都被双重缓冲。

这需要覆盖CreateParams:

protected override CreateParams CreateParams
{
    get
    {
        CreateParams cp = base.CreateParams;
        cp.ExStyle |= 0x02000000;  // Turn on WS_EX_COMPOSITED
        return cp;
    }
}

摘要

SetStyle在控制级完成任务,CreateParam在表单级完成任务

学分:

@terrybozzlo,@Caramiriel,@HansPassant