使用 WS_EX_COMPOSITED 实现无闪烁选项卡控件

发布于 2024-10-02 18:34:38 字数 995 浏览 0 评论 0原文

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

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

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

我尝试的解决方案是使 CFrameWindowImpl 派生类使用 WS_EX_COMPOSITED 样式,并且其下面的所有窗口都使用 WS_EX_TRANSPARENT< /代码> 风格。不幸的是,这使得选项卡控件按钮显示为空黑条,并且任何配置视图的控件根本不显示。

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

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

谢谢, 保罗


编辑: 成功了。我按照 Mark Ransom 的建议删除了所有 WS_EX_TRANSPARENT 样式。我将 WS_EX_COMPOSITED 样式仅放在 CTabCtrl(包含在 CTabView 内)上。其他控件根据需要通过 WTL::CDoubleBufferImpl<> 获得双缓冲。

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.

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 CFrameWindowImpl derived class use the WS_EX_COMPOSITED style and all windows beneath it use the WS_EX_TRANSPARENT style. 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.

If I remove the WS_EX_COMPOSITED and WS_EX_TRANSPARENT styles, the form displays properly, but the CTabView and everything beneath it flickers horribly when resized.

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_TRANSPARENT styles per Mark Ransom's suggestion. I put the WS_EX_COMPOSITED style on only the CTabCtrl (contained within the CTabView). Other controls get double-buffering as needed through WTL::CDoubleBufferImpl<>.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

染墨丶若流云 2024-10-09 18:34:38

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

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

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.

葵雨 2024-10-09 18:34:38

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

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

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

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

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.

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

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.

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

东京女 2024-10-09 18:34:38

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

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).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文