简体   繁体   English

双缓冲公共控件

[英]Double buffer common controls

Is there a way to double-buffer the common controls ? 有没有办法双重缓冲共同控件 Currently when they resize they flicker. 目前,当他们调整大小时,他们闪烁。 A lot..... 很多.....

EDIT: If it helps, it is a bunch of button controls and a few edit controls, all sitting on top of a tab control. 编辑:如果它有帮助,它是一组按钮控件和一些编辑控件,都位于选项卡控件的顶部。 The Tab control redraws itself, then the buttons redraw themselves. Tab控件重绘自身,然后按钮重绘自己。 When the buttons redraw, they flicker. 当按钮重绘时,它们会闪烁。

EDIT2: Here's an example of the problem I'm having: http://billy-oneal.com/Lobfuscator.exe EDIT2:这是我遇到的问题的一个例子: http//billy-oneal.com/Lobfuscator.exe

I understand the topic is quite old, but this may be relevant to someone who's running into trouble with a flicker problem. 我知道这个话题已经很老了,但这可能与遇到闪烁问题的人有关。

Very much like Billy, I have run into an issue that pops up when switching tabs, where controls that are placed on the tab flicker when being shown and hidden. 非常像Billy,我遇到了一个问题,当切换标签时会弹出一个问题,当显示和隐藏时,放置在标签上的控件会闪烁。 For reference, I'm using ShowWindow function extensively to hide and show controls. 作为参考,我广泛使用ShowWindow函数来隐藏和显示控件。

I have been fiddling with WS_EX_COMPOSITED for a few hours and it gave me very odd results. 我一直在摆弄WS_EX_COMPOSITED几个小时,它给了我非常奇怪的结果。 I'm also not resizing anything, the dialog is designed to run fullscreen and it adapts to the current desktop resolution. 我也没有调整任何大小,对话框设计为全屏运行,它适应当前的桌面分辨率。

This is the layout of my dialog, which I have created manually, calling the CreateWindowEx function for every control: 这是我手动创建的对话框的布局,为每个控件调用CreateWindowEx函数:

Main window -- some controls -- tab control ---- some more controls 主窗口 - 一些控件 - 选项卡控件----更多控件

Indent represents the parent-child relations. 缩进代表父子关系。 The tab control has WS_CHILD and WS_CLIPCHILDREN styles set on creation, all of the controls have WS_CHILD style set. 选项卡控件在创建时设置了WS_CHILD和WS_CLIPCHILDREN样式,所有控件都设置了WS_CHILD样式。

What in the end did the trick was the following 最终诀窍是什么呢?

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

This bit is written in assembly (MASM32), but I'm sure you get the gist of it. 这个位是用汇编语言(MASM32)编写的,但我确信你会得到它的要点。 Simply, get the EX_STYLE of your main window sometime during WM_INITDIALOG and add WS_EX_COMPOSITED to it. 简单地说,在WM_INITDIALOG期间的某个时间获取主窗口的EX_STYLE并向其添加WS_EX_COMPOSITED。

In this singular case, this method works both on 32bit Windows XP SP3 and 64bit Windows 7 SP1. 在这个单一的情况下,这种方法适用于32位Windows XP SP3和64位Windows 7 SP1。 There was no need to add the WS_EX_COMPOSITED style to any of the tab's child controls (some of the static controls I use have WS_EX_TRANSPARENT set, but that's for other reasons) and at this time there is no apparent need to return non-zero on WM_ERASEBKGND message. 没有必要将WS_EX_COMPOSITED样式添加到任何选项卡的子控件(我使用的一些静态控件设置了WS_EX_TRANSPARENT,但这是出于其他原因),此时没有明显需要在WM_ERASEBKGND上返回非零值信息。 I'm also not experiencing any performance problems on a moderately powerful C2D machine. 我也没有在中等强大的C2D机器上遇到任何性能问题。

For reference, this is my 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

There's nothing special here, neither. 这里没有什么特别的,也没有。 I'm setting the "dialog control grey" as the background color and using the CS_*REDRAW styles, those appear not to affect this situation. 我将“对话框控件灰色”设置为背景颜色并使用CS_ * REDRAW样式,这些似乎不会影响这种情况。 The "empty" dialog template I used to create the main windows is this 我用来创建主窗口的“空”对话框模板就是这个

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

Hopefully this may save some time to people looking for answers. 希望这可以为寻找答案的人节省一些时间。 It's a tad long, but I wanted to detail it as much as possible. 这有点长,但我想尽可能详细地说明一下。

Regards. 问候。

Look at using WS_EX_COMPOSITED and WS_EX_TRANSPARENT styles. 查看使用WS_EX_COMPOSITEDWS_EX_TRANSPARENT样式。 They provide doublebuffering, altough WM_PAINT will be called when the underlying bitmap is finished drawing, since it draws child controls from bottom to top, so you can paint only in your window procedure. 它们提供双重缓冲,当底层位图完成绘制时,将调用WM_PAINT,因为它从下到上绘制子控件,因此您只能在窗口过程中绘制。 I've used it in the past and work pretty well. 我过去曾经使用它并且工作得很好。

Set your top-level window (container) to extended style WS_EX_COMPOSITED and your child windows with WS_EX_TRANSPARENT. 将顶级窗口(容器)设置为扩展样式WS_EX_COMPOSITED,将子窗口设置为WS_EX_TRANSPARENT。 Also, remember to define: 另外,请记住定义:

#define WINVER 0x501 

See CreateWindowEx for information on the composited style. 有关合成样式的信息,请参阅CreateWindowEx This also makes possible to do perpixel transparency on child windows. 这也使得在子窗口上实现每像素透明度成为可能。

UPDATE UPDATE

What about usign WM_PRINTCLIENT to transfer the client area to a bitmap on a DC and blit all the client area as a whole? 如何使用WM_PRINTCLIENT将客户区传输到DC上的位图并将整个客户区作为整体进行blit?

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

Larry Osterman recently blogged about this subject; 拉里奥斯特曼最近在博客上写了这个主题; you might find some interesting details there . 你可能会在那里找到一些有趣的细节

indeed, 确实,

someone posted an answer for this on one of my posts a while ago. 有人刚才在我的一个帖子上发布了这个问题的答案。 Check it out: Here 看看: 这里

and be sure to upvote him for being awesome. 并且一定要赞美他的真棒。

The code is C#, hopefully there is a simple translation. 代码是C#,希望有一个简单的翻译。

Without knowing exactly what you're doing, I assume you're using either MFC or Win32 C for this. 在不确切知道你在做什么的情况下,我假设你正在使用MFC或Win32 C。

You probably want to do the resize on WM_SIZE message. 您可能想要对WM_SIZE消息进行大小调整。 I'm not sure where you're resizing the controls, but I think you're doing it while it's being resized, which is why it's causing the flicker. 我不确定你在哪里调整控件的大小,但我认为你在调整大小的时候就是这样做了,这就是为什么它会导致闪烁。

Also, I'm thinking but I don't know, you could probably use the SetWindowPos function, and for the uFlags, have SWP_NOREDRAW. 另外,我在想,但我不知道,你可能会使用SetWindowPos函数,对于uFlags,你可以使用SWP_NOREDRAW。 Though I'm not sure how great this would work for common controls. 虽然我不确定这对普通控制有多好。

You can create a memory device context, MemDC at the very start. 您可以在一开始就创建一个内存设备上下文MemDC。 Draw everything into the MemDC, then when the window recieves a WM_PAINT message or is invalidated, copy the MemDC to the real DC by bit blitting. 将所有内容绘制到MemDC中,然后当窗口收到WM_PAINT消息或无效时,通过位blitting将MemDC复制到实际DC。

I remember reading up the technique by Herbert Schildt in his book a few years back (Windows 98 Programming from the Ground Up). 我记得几年前Herbert Schildt在他的书中阅读了这项技术(Windows 98 Programming from the Ground Up)。 In that way, all the redrawing is faster as you blit the memory dc to the real dc. 这样,当你将内存直流电压到实际直流时,所有的重绘都会更快。 But the one big gotcha, was how big the memory dc you want to use! 但是最重​​要的一点是,你想要使用的内存直流有多大! But he showed how to do it. 但他展示了如何做到这一点。 There is a code download for all of the chapters in that book published by Osborne McGraw Hill. Osborne McGraw Hill出版的那本书的所有章节都有代码下载。

Hope this helps, Best regards, Tom. 希望这会有所帮助,最好的问候,汤姆。

You're not using WS_EX_TRANSPARENT, are you? 你没有使用WS_EX_TRANSPARENT,是吗? That will cause underlying windows to be painted before the controls, and when the bottom window erases you get flicker. 这将导致在控件之前绘制底层窗口,当底部窗口擦除时,您会闪烁。

We use WTL::CDoubleBufferImpl mix-in for that purpose. WTL::CDoubleBufferImpl我们使用WTL::CDoubleBufferImpl混合。 We even draw stuff with GDI+ over. 我们甚至用GDI +绘制东西。 Zero flickering. 零闪烁。

Usage is pretty simple: you just public-ly inherit from WTL::CDoubleBufferImpl<YourClass> , and chain it in the ATL message map. 用法非常简单:您只需公开继承WTL::CDoubleBufferImpl<YourClass> ,并将其链接到ATL消息映射中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM