为啥即使在调用 UpdateWindow() 之后绘制消息也会丢失?
Posted
技术标签:
【中文标题】为啥即使在调用 UpdateWindow() 之后绘制消息也会丢失?【英文标题】:Why paint messages get lost even after calling UpdateWindow()?为什么即使在调用 UpdateWindow() 之后绘制消息也会丢失? 【发布时间】:2010-02-05 13:25:00 【问题描述】:我有一个具有以下 Windows 层次结构的应用程序:
W1
-W2 (Child of W1)
- W3 ( Child of W2)
--------------------|
| W1|------------| |
| |W2 |------| | |
| | |W3 | | |
| | |------| | |
| |------------| |
|-------------------|
当 W2 发生某些事件时,我会调用 UpdateWindow
:
W2::onCertainEvent()
Invalidate(NULL);
UpdateWindow();
W2 的OnPaint
处理如下所示:
W2::onPaint()
//W2 logic goes here
W3.Invalidate(NULL); //So that paint messages are given to W3
但有时绘图消息会在 W2 中丢失。虽然UpdateWindow
被调用,但没有对应的OnPaint
() 被调用。
如果我将属性 WS_EX_TRANSPARENT
添加到 W1(W2 的父级),则始终会收到 @ W2 的绘制消息。
但是添加 WS_EX_TRANSPARENT
标志的问题是,当我调整窗口 W1 的大小时,它会产生很多闪烁。
我的问题是:
1. W2 有什么问题导致Paint 消息丢失?
2.为什么添加WS_EX_TRANSPARENT
可以解决Paint问题。
3. 使用flag如何解决闪烁问题。
谢谢,
【问题讨论】:
【参考方案1】:闪烁
闪烁可以通过提交WM_ERASEBKGND
并确保它什么都不做来解决。闪烁可能是因为每个窗口在每次绘制之前都会处理此消息,以使用其背景颜色擦除无效区域。如果您处理它并且什么都不做,则不会发生擦除 - 只需确保您的 WM_PAINT
处理程序绘制整个无效区域,否则您将留下先前绘制的伪影。
但是,在这种情况下,我认为闪烁的发生是因为 W1 先绘制自身,然后是 W2,然后是 W3 每次绘制。这表明WS_EX_TRANSPARENT
不是解决您遇到的问题的方法。
缺少 WM_PAINT 很难知道如何追踪它。在 .NET 中,发生这种情况是因为子窗口遮盖了控件的整个客户区,因此不会传播绘制消息,但我相信这是特定的 .NET 行为。如果你能提供一个展示问题的示例项目或示例代码,那将是一个很大的帮助。
与此同时,您可以移除 W3 以使 W2 不会被遮挡,然后查看您的所有绘制消息是否都返回。另外,请注意CWnd::Invalidate
不采用 NULL 作为选项,它采用 BOOL
(TRUE
或 FALSE
)。
【讨论】:
【参考方案2】:WM_PAINT “消息”并不是正常意义上的消息。它们的行为很像每个窗口消息队列末尾的标志。它们不通过线程消息队列,它们在 Windows 消息队列中没有位置。它们是在您尝试从 Windows 消息队列中检索消息时生成的,并且没有其他消息。那时,会考虑所有不同的失效,并生成一个或多个 (!) WM_PAINT。
结果是,在您的W2::onCertainEvent()
之后,“窗口无效”标志将被设置。因此,最终会调用WM_PAINT
,但随后生成的 WM_PAINT 不会专门用于该“特定事件”。
历史背景是,如果有很多消息未决,您不希望花费太多时间来绘制窗口,因为这些消息可能只会使您的窗口无效。最好先让你的模型更新,然后再做视图。
【讨论】:
以上是关于为啥即使在调用 UpdateWindow() 之后绘制消息也会丢失?的主要内容,如果未能解决你的问题,请参考以下文章
为啥即使在添加程序集“Microsoft.SqlServer.ConnectionInfo”之后 C# 也无法识别 Server()
为啥在组件加载时不调用 useEffect(()=...,[]) ?
为啥我得到“UnhandledPromiseRejectionWarning:错误:未定义类型错误。确保提供显式类型”即使在我指定了类型之后?