有没有一种方法可以对常用控件进行双缓冲处理?当前,当它们调整大小时会出现很多闪烁……
编辑:如果有帮助的话,这是一堆按钮控件和一些编辑控件,都位于选项卡控件之上。选项卡控件重新绘制自己,然后按钮控件重新绘制自己。当按钮重新绘制时,它们会闪烁。
编辑2:这是我遇到的问题示例: http://billy-oneal.com/Lobfuscator.exe
有没有一种方法可以对常用控件进行双缓冲处理?当前,当它们调整大小时会出现很多闪烁……
编辑:如果有帮助的话,这是一堆按钮控件和一些编辑控件,都位于选项卡控件之上。选项卡控件重新绘制自己,然后按钮控件重新绘制自己。当按钮重新绘制时,它们会闪烁。
编辑2:这是我遇到的问题示例: http://billy-oneal.com/Lobfuscator.exe
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
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
考虑使用 WS_EX_COMPOSITED
和 WS_EX_TRANSPARENT
样式。它们提供了双缓冲,尽管当底层位图完成绘制时会调用 WM_PAINT,因为它从下到上绘制子控件,所以你只能在窗口过程中绘制。我之前用过它,效果还不错。
将顶层窗口(容器)设置为扩展样式 WS_EX_COMPOSITED,将子窗口设置为 WS_EX_TRANSPARENT。此外,请记住定义:
#define WINVER 0x501
请参考CreateWindowEx了解混合样式信息。这也使得子窗口可以进行每像素透明度。
更新
使用WM_PRINTCLIENT将客户端区域传输到DC上的位图,并作为一个整体复制整个客户端区域怎么样?
WS_CLIPSIBLINGS
风格 - 我只是使用了 WS_CLIPCHILDREN
,因为子控件不是选项卡控件的子控件,而是我的窗口的子控件,所以它是无效的。这似乎已经解决了选项卡控件的问题。(所以如果没有人回答我的问题,你将获得此赏金)然而,任何静态控件在调整大小时仍会闪烁 - 我怀疑这是静态控件的问题,如果可能的话,我仍然希望能够双缓冲它们... - Billy ONealWS_EX_COMPOSITED
添加到容器中,解决了我的丑陋的多行编辑控件闪烁问题(它占据了窗口的90%)。显然不需要WS_EX_TRANSPARENT
,它会引起一些奇怪的背景问题。 - quantum如果不知道你在做什么,我猜测你可能正在使用MFC或Win32 C。
你可能想在WM_SIZE消息上进行调整大小。我不确定你在哪里调整控件的大小,但我认为你是在它被调整大小时进行调整,这就是为什么会导致闪烁的原因。
此外,我在思考但不确定,你可能可以使用SetWindowPos函数,并对于uFlags,使用SWP_NOREDRAW。虽然我不确定这对于常规控件的效果如何。
你可以在最开始创建一个内存设备上下文MemDC。将所有内容绘制到MemDC中,然后当窗口接收到WM_PAINT消息或被无效化时,通过位块传输将MemDC复制到真实的DC中。
我记得几年前在Herbert Schildt的书中(《Windows 98 Programming from the Ground Up》)读到了这种技术。这样做的好处是,由于将内存dc传输到真实dc中,因此所有的重绘都更快。但是有一个很大的问题,就是你想要使用多大的内存dc!但他展示了如何解决这个问题。该书由Osborne McGraw Hill出版,其中包含所有章节的代码下载。
希望这能帮到你, 最好的祝愿, 汤姆。
你没有使用WS_EX_TRANSPARENT,是吗?这会导致底层窗口在控件之前被绘制,当底层窗口擦除时会出现闪烁。
WTL::CDoubleBufferImpl
混入来实现这个目的。我们甚至使用 GDI+ 进行绘图,完全没有闪烁。WTL::CDoubleBufferImpl<YourClass>
,并将其链接到 ATL 消息映射中即可。