有没有办法对常用控件进行双重缓冲?目前,当他们调整大小时,它们会闪烁。很多.....
编辑:如果有帮助,它是一堆按钮控件和一些编辑控件,都位于选项卡控件的顶部。Tab 控件重绘自身,然后按钮重绘自身。当按钮重绘时,它们会闪烁。
EDIT2:这是我遇到的问题的一个例子:http: //billy-oneal.com/Lobfuscator.exe
有没有办法对常用控件进行双重缓冲?目前,当他们调整大小时,它们会闪烁。很多.....
编辑:如果有帮助,它是一堆按钮控件和一些编辑控件,都位于选项卡控件的顶部。Tab 控件重绘自身,然后按钮重绘自身。当按钮重绘时,它们会闪烁。
EDIT2:这是我遇到的问题的一个例子:http: //billy-oneal.com/Lobfuscator.exe
看看使用WS_EX_COMPOSITED
和WS_EX_TRANSPARENT
样式。它们提供双缓冲,尽管当底层位图完成绘制时会调用 WM_PAINT,因为它从底部到顶部绘制子控件,因此您只能在窗口过程中绘制。我过去使用过它并且工作得很好。
将您的顶级窗口(容器)设置为扩展样式 WS_EX_COMPOSITED,并将您的子窗口设置为 WS_EX_TRANSPARENT。另外,请记住定义:
#define WINVER 0x501
有关复合样式的信息,请参见CreateWindowEx。这也使得在子窗口上进行逐像素透明成为可能。
更新
使用 WM_PRINTCLIENT 将客户区传输到 DC 上的位图并将所有客户区作为一个整体进行 blit 怎么样?
我知道这个话题已经很老了,但这可能与遇到闪烁问题的人有关。
非常像比利,我遇到了切换选项卡时弹出的问题,其中放置在选项卡上的控件在显示和隐藏时会闪烁。作为参考,我广泛使用 ShowWindow 函数来隐藏和显示控件。
我一直在摆弄 WS_EX_COMPOSITED 几个小时,它给了我非常奇怪的结果。我也没有调整任何大小,该对话框旨在全屏运行,并适应当前的桌面分辨率。
这是我手动创建的对话框的布局,为每个控件调用 CreateWindowEx 函数:
主窗口 -- 一些控件 -- 选项卡控件 ---- 更多控件
缩进代表父子关系。选项卡控件在创建时设置了 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
希望这可以为寻找答案的人们节省一些时间。它有点长,但我想尽可能详细地说明它。
问候。
拉里奥斯特曼最近在博客上讨论了这个主题;你可能会在那里找到一些有趣的细节。
在不确切知道您在做什么的情况下,我假设您为此使用 MFC 或 Win32 C。
您可能想要调整 WM_SIZE 消息的大小。我不确定你在哪里调整控件的大小,但我认为你是在调整大小的时候做的,这就是它导致闪烁的原因。
另外,我在想,但我不知道,你可能可以使用 SetWindowPos 函数,对于 uFlags,有 SWP_NOREDRAW。虽然我不确定这对常用控件有多好。
您可以在一开始就创建内存设备上下文 MemDC。将所有内容绘制到 MemDC 中,然后当窗口收到 WM_PAINT 消息或失效时,通过位 blitting 将 MemDC 复制到真实 DC。
我记得几年前在 Herbert Schildt 的书中阅读了该技术(Windows 98 Programming from the Ground Up)。这样一来,当您将内存 dc blit 到真正的 dc 时,所有重绘都会更快。但一个大问题是你想使用多大的内存 dc!但他展示了如何做到这一点。Osborne McGraw Hill 出版的这本书的所有章节都有一个代码下载。
希望这会有所帮助,最好的问候,汤姆。
您没有使用 WS_EX_TRANSPARENT,是吗?这将导致在控件之前绘制底层窗口,并且当底部窗口擦除时,您会闪烁。
WTL::CDoubleBufferImpl
为此,我们使用混入。我们甚至用 GDI+ 来绘制东西。零闪烁。
用法非常简单:您只需公开继承自WTL::CDoubleBufferImpl<YourClass>
,并将其链接到 ATL 消息映射中。