【问题标题】:Double buffer common controls双缓冲常用控件
【发布时间】:2010-12-22 23:28:51
【问题描述】:

有没有办法对common controls 进行双重缓冲?目前,当他们调整大小时,它们会闪烁。很多.....

编辑:如果有帮助的话,它是一堆按钮控件和一些编辑控件,所有这些都位于选项卡控件的顶部。 Tab 控件重绘自身,然后按钮重绘自身。当按钮重绘时,它们会闪烁。

EDIT2:这是我遇到的问题的一个示例: http://billy-oneal.com/Lobfuscator.exe

【问题讨论】:

  • 这里缺少很多东西。什么版本的 Windows?什么版本的常用控件?你是如何调整大小的?
  • 1.不管我用什么版本。 2. 6. 3. DeferWindowPos()

标签: c++ winapi control-library


【解决方案1】:

看看使用WS_EX_COMPOSITEDWS_EX_TRANSPARENT样式。它们提供双缓冲,尽管当底层位图完成绘制时会调用 WM_PAINT,因为它从下到上绘制子控件,因此您可以在窗口过程中绘制 only。我过去使用过它并且工作得很好。

将您的顶级窗口(容器)设置为扩展样式 WS_EX_COMPOSITED,并将您的子窗口设置为 WS_EX_TRANSPARENT。另外,记得定义:

#define WINVER 0x501 

有关复合样式的信息,请参阅CreateWindowEx。这也使得在子窗口上实现逐像素透明成为可能。

更新

如何使用 WM_PRINTCLIENT 将客户区传输到 DC 上的位图并将所有客户区作为一个整体进行 blit?

http://blogs.msdn.com/larryosterman/archive/2008/08/27/larry-s-new-favorite-windows-message-wm-printclient.aspx

【讨论】:

  • 我会调查的。可能只是得到复选标记..我只需要确保它有效。除非有人想出适用于 Win2k 的解决方案......
  • 嗯...没用。仍然闪烁。似乎它是对每个单独的子控件单独进行双重缓冲,但不是子控件作为一个整体来控制自己。这,选项卡控件下方的控件仍然闪烁:(
  • 对不起。您使用的是 WS_CLIP_SIBLINGS 和 WS_CLIPCHILDREN 样式吗?
  • 我已经更新了我的答案。检查一下,我从未使用过 WM_PRINTCLIENT,但可能会对您有所帮助。
  • 不要忘记 Larry 的后续帖子 Herman,他在其中解释说 WM_PRINTCLIENT 是一个丑陋的 hack,它只是掩盖了问题(同时导致了其他问题),而不是实际修复闪烁。 blogs.msdn.com/larryosterman/archive/2009/09/16/…
【解决方案2】:

我知道这个话题已经很老了,但这可能与遇到闪烁问题的人有关。

与 Billy 非常相似,我遇到了一个在切换选项卡时弹出的问题,其中放置在选项卡上的控件在显示和隐藏时会闪烁。作为参考,我广泛使用 ShowWindow 函数来隐藏和显示控件。

我一直在摆弄 WS_EX_COMPOSITED 几个小时,它给了我非常奇怪的结果。我也没有调整任何大小,该对话框旨在全屏​​运行,并适应当前的桌面分辨率。

这是我手动创建的对话框的布局,为每个控件调用 CreateWindowEx 函数:

主窗口 -- 一些控制 -- 选项卡控件 ---- 更多控件

Indent 表示父子关系。选项卡控件在创建时设置了 WS_CHILD 和 WS_CLIPCHILDREN 样式,所有控件都设置了 WS_CHILD 样式。

最后的诀窍是如下

MainProc proc hWnd:DWORD,uMsg:DWORD,wParam:DWORD,lParam:DWORD
    mov eax,uMsg
    cmp eax,WM_INITDIALOG
    je @WM_INITDIALOG
    ...

    invoke DefWindowProc,hWnd,uMsg,wParam,lParam
    ret

@WM_INITDIALOG:
    ...

    invoke GetWindowLong,hWnd,GWL_EXSTYLE
    or eax,WS_EX_COMPOSITED
    invoke SetWindowLong,hWnd,GWL_EXSTYLE,eax
    ...

MainProc endp

这部分是用汇编语言 (MASM32) 编写的,但我相信您已经明白了其中的要点。简单地说,在 WM_INITDIALOG 期间获取主窗口的 EX_STYLE 并将 WS_EX_COMPOSITED 添加到其中。

在这种特殊情况下,此方法适用于 32 位 Windows XP SP3 和 64 位 Windows 7 SP1。无需将 WS_EX_COMPOSITED 样式添加到选项卡的任何子控件(我使用的一些静态控件设置了 WS_EX_TRANSPARENT,但这是出于其他原因),此时显然不需要在 WM_ERASEBKGND 上返回非零信息。我在中等强大的 C2D 机器上也没有遇到任何性能问题。

作为参考,这是我的主要

Main proc hInst:DWORD,hPrevInst:DWORD,CmdLine:DWORD,CmdShow:DWORD
    LOCAL wc:WNDCLASSEX,msg:MSG

    mov wc.cbSize,sizeof WNDCLASSEX
    mov wc.style,CS_HREDRAW or CS_VREDRAW
    mov wc.lpfnWndProc,offset MainProc
    mov wc.cbClsExtra,NULL
    mov wc.cbWndExtra,DLGWINDOWEXTRA
    push hInst
    pop wc.hInstance
    mov wc.hbrBackground,COLOR_BTNFACE+1
    mov wc.lpszClassName,offset szClassName
    invoke LoadIcon,NULL,IDI_APPLICATION
    mov wc.hIcon,eax
    mov wc.hIconSm,eax
    invoke LoadCursor,NULL,IDC_ARROW
    mov wc.hCursor,eax
    invoke RegisterClassEx,addr wc
    invoke CreateDialogParam,hInstance,IDD_MAIN,NULL,addr MainProc,NULL
    invoke ShowWindow,hWin,SW_SHOWNORMAL
    invoke UpdateWindow,hWin
    invoke LoadAccelerators,hInstance,IDD_ACC_TABLE
    mov hAcc,eax
    jmp @2
@1:
    invoke TranslateAccelerator,hWin,hAcc,addr msg
    test eax,eax
    jne @2
    invoke TranslateMessage,addr msg
    invoke DispatchMessage,addr msg
@2:
    invoke GetMessage,addr msg,NULL,0,0
    test eax,eax
    jne @1

    mov eax,msg.wParam
    ret

Main endp

这里也没有什么特别之处。我将“对话框控件灰色”设置为背景颜色并使用 CS_*REDRAW 样式,这些似乎不会影响这种情况。 我用来创建主窗口的“空”对话框模板是这样的

IDD_MAIN DIALOGEX 0,0,318,177
FONT 8,"MS Sans Serif",0,0,0
CLASS "DLGCLASS"
STYLE 0x90800000
EXSTYLE 0x00000008
BEGIN
END

希望这可以为寻找答案的人们节省一些时间。有点长,但我想尽可能详细。

问候。

【讨论】:

    【解决方案3】:

    Larry Osterman 最近写了一篇关于这个主题的博客;你可能会发现一些有趣的细节there

    【讨论】:

    • 如果可以避免的话,我宁愿不必完全重新实现win32选项卡控件。
    • 但关键的观察是底层控件(在您的情况下为 Tab 控件)正在导致其子级重绘。双缓冲单个控件将无济于事。您要么需要确保它们不会失效,要么需要一种将所有绘图缓冲到窗口的方法。 Osterman 最初的方法是使用 WM_PRINTCLIENT hack 进行缓冲,但这导致了其他问题。他的最终解决方案不涉及重新实现整个控件,只是绘画,这主要是几个函数调用。
    • 选项卡控件比分组框要复杂得多。让它正常工作不仅仅是“绘画”。
    【解决方案4】:

    确实,

    不久前有人在我的一篇帖子上发布了这个答案。看看吧:Here

    并确保为他的出色表现点赞。

    代码是C#,希望有简单的翻译。

    【讨论】:

    • 没有。 .NET 中的控件与 Win32 中的控件无关。
    • 您在写问题时没有说它是win32。 Pascal Couq 在我发布后添加了标签。
    • 如果您注意到该链接,它会转到 Win32 常用控件页面。我还注意到 .NET 并不称它们为“通用控件”。
    • 另外(对 Jruds 的评论)链接页面上提供的解决方案实际上设置了 WS_EX_COMPOSITED ......其他人给出的解决方案......由于操作系统是 Windows,这不是一个常见的控制问题,而是关于如何重绘 Windows 的问题,他的建议是有效的......
    【解决方案5】:

    在不确切知道您在做什么的情况下,我假设您为此使用 MFC 或 Win32 C。

    您可能想要调整 WM_SIZE 消息的大小。我不确定您在哪里调整控件的大小,但我认为您是在调整大小的同时进行的,这就是导致闪烁的原因。

    另外,我在想,但我不知道,你可能会使用 SetWindowPos 函数,而对于 uFlags,有 SWP_NOREDRAW。虽然我不确定这对常用控件有多大作用。

    【讨论】:

    • 选项卡控件(我的窗口本质上是一个大选项卡控件)需要重新绘制然后调整大小。这就是为什么我首先需要双缓冲区。
    【解决方案6】:

    您可以在一开始就创建内存设备上下文 MemDC。将所有内容绘制到 MemDC 中,然后当窗口收到 WM_PAINT 消息或失效时,通过位 blitting 将 MemDC 复制到真正的 DC。

    我记得几年前 Herbert Schildt 在他的书中阅读了该技术(Windows 98 Programming from the Ground Up)。这样一来,当您将内存 dc blit 到真正的 dc 时,所有重绘都会更快。但一个大问题是你想使用多大的内存 dc!但他展示了如何做到这一点。 Osborne McGraw Hill 出版的那本书的所有章节都有代码下载。

    希望这会有所帮助, 最好的祝福, 汤姆。

    【讨论】:

    • 是的,但这对我没有帮助,因为我不是画图的人。公共控制应该是这样做的。我没有收到子控件的 WM_PAINT 消息。
    • “大”多年来发生了变化。 1920x1200 全屏只有 7MB。
    • 不知道你从哪里得到那个数学勒索姆先生。 1920x1200x32 为 737280000 位,即 87.89MB
    • 我乘以 1920*1200*3,我的答案是兆字节而不是兆比特。
    • 但这将是每个像素四个字节(假设 32 位颜色),1920*1200*4 ~= 9 MB
    【解决方案7】:

    您没有使用 WS_EX_TRANSPARENT,是吗?这将导致在控件之前绘制底层窗口,并且当底部窗口擦除时您会闪烁。

    【讨论】:

    • 我什至不知道那是什么。
    【解决方案8】:

    为此,我们使用WTL::CDoubleBufferImpl mix-in。我们甚至用 GDI+ 来绘制东西。零闪烁。

    使用非常简单:您只需公开继承 WTL::CDoubleBufferImpl<YourClass>,并将其链接到 ATL 消息映射中。

    【讨论】:

    猜你喜欢
    • 2011-05-04
    • 1970-01-01
    • 2010-09-15
    • 1970-01-01
    • 2013-08-14
    • 1970-01-01
    • 2011-03-05
    • 2011-08-20
    • 2011-04-23
    相关资源
    最近更新 更多