windows 带有 WS_EX_COMPOSITED 的无闪烁标签控制

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4188306/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 15:36:23  来源:igfitidea点击:

flicker free tab control with WS_EX_COMPOSITED

c++windowsflickerwtl

提问by PaulH

I have a VS2008 C++ application for Windows XP SP3 developed using WTL 8.1. My application contains a tab control that flickers when the application border is resized.

我有一个使用 WTL 8.1 开发的适用于 Windows XP SP3 的 VS2008 C++ 应用程序。我的应用程序包含一个选项卡控件,当应用程序边框调整大小时该控件会闪烁。

My window hierarchy looks like this:

我的窗口层次结构如下所示:

CFrameWindowImpl   CMainFrm
|-CSplitterWindow  Splitter
  |-CTabView       Configuration Tabs
  | |-CDialogImpl  Configuration View 1
  | |-CDialogImpl  Configuration View 2
  | |-CDialogImpl  Configuration View 3
  |-CDialogImpl    Control View

The solution I'm trying is to make the CFrameWindowImplderived class use the WS_EX_COMPOSITEDstyle and all windows beneath it use the WS_EX_TRANSPARENTstyle. Unfortunately, this makes the tab control buttons show as an empty black bar and the controls of any Configuration View to not show at all.

我正在尝试的解决方案是让CFrameWindowImpl派生类使用该WS_EX_COMPOSITED样式,并且它下面的所有窗口都使用该WS_EX_TRANSPARENT样式。不幸的是,这使得选项卡控件按钮显示为一个空的黑条,并且任何配置视图的控件根本不显示。

If I remove the WS_EX_COMPOSITEDand WS_EX_TRANSPARENTstyles, the form displays properly, but the CTabViewand everything beneath it flickers horribly when resized.

如果我删除WS_EX_COMPOSITEDWS_EX_TRANSPARENT样式,表单会正确显示,但是CTabView当调整大小时,它下面的所有内容都会可怕地闪烁。

What do I need to change to eliminate the flicker and draw the controls properly?

我需要更改什么才能消除闪烁并正确绘制控件?

Thanks, PaulH

谢谢,保罗



Edit: Got it working. I removed all the WS_EX_TRANSPARENTstyles per Mark Ransom's suggestion. I put the WS_EX_COMPOSITEDstyle on onlythe CTabCtrl(contained within the CTabView). Other controls get double-buffering as needed through WTL::CDoubleBufferImpl<>.

编辑:让它工作。我WS_EX_TRANSPARENT根据 Mark Ransom 的建议删除了所有样式。我把WS_EX_COMPOSITED风格上唯一CTabCtrl(包含内CTabView)。其他控件根据需要通过WTL::CDoubleBufferImpl<>.

采纳答案by Mark Ransom

A window flickers because it gets erased before it's drawn. To eliminate this you need to disable erasing of the window entirely and use double buffering - draw the window contents into a bitmap, then copy the bitmap to the window. Because the bitmap contains the entire contents including the background, there's no need to erase anymore.

窗口闪烁是因为它在绘制之前被擦除。要消除这种情况,您需要完全禁用窗口擦除并使用双缓冲 - 将窗口内容绘制到位图中,然后将位图复制到窗口中。由于位图包含包括背景在内的全部内容,因此无需再擦除。

It looks like WS_EX_COMPOSITED will handle the double buffering automatically, but you still probably need to use a NULL background brush and/or handle the WM_ERASEBKGND message.

看起来 WS_EX_COMPOSITED 会自动处理双缓冲,但您可能仍然需要使用 NULL 背景画笔和/或处理 WM_ERASEBKGND 消息。

回答by Chris Becke

Whats not mentioned in MSDN is that the Desktop Window Manager - the component that hooks window painting on Windows Vista and 7 to perform the desktop composition necessary to get the aero glass effect - does NOT implement WS_EX_COMPOSITED.

MSDN 中没有提到的是,桌面窗口管理器 - 在 Windows Vista 和 7 上挂钩窗口绘制以执行获得航空玻璃效果所需的桌面组合的组件 - 没有实现 WS_EX_COMPOSITED。

Which means all the work you put into getting this style to work on XP, is doomed to become irrelevent on Vista or later.

这意味着您为让这种风格在 XP 上运行而付出的所有努力,注定在 Vista 或更高版本上变得无关紧要。

The other problem with WS_EX_COMPOSITED - and why it was an optional style and not a default on XP: The double buffering only picks up painting performed during the BeginPaint / EndPaint block of the parent window. Lots of, even standard controls, perform painting outside of their WM_PAINT handlers, and as a result the backbuffer gets only partially painted.

WS_EX_COMPOSITED 的另一个问题 - 以及为什么它是可选样式而不是 XP 上的默认样式:双缓冲仅拾取在父窗口的 BeginPaint / EndPaint 块期间执行的绘画。许多,甚至是标准控件,在它们的 WM_PAINT 处理程序之外执行绘制,因此后台缓冲区仅部分绘制。

Sadly, the result is, the only way to "eliminate" flicker in native API apps is to try to minimize it: WS_CLIPCHILDREN and WS_CLIPSIBLINGS can help if you dont have overlapping controls - to ensure that each control's area is painted only once. And ensure that the main dialog does not perform any flood filling in WM_ERASEBKGND

可悲的是,结果是,在本机 API 应用程序中“消除”闪烁的唯一方法是尝试将其最小化:如果您没有重叠控件,WS_CLIPCHILDREN 和 WS_CLIPSIBLINGS 可以提供帮助 - 确保每个控件的区域只绘制一次。并确保主对话框不会在 WM_ERASEBKGND 中执行任何洪水填充

回答by Mordachai

It is not, in my experience, possible to use double-buffering for anything that contains child controls (unless they all fully support WM_PRINT, which most do not).

根据我的经验,不可能对包含子控件的任何东西使用双缓冲(除非它们都完全支持 WM_PRINT,而大多数不支持)。