为什么即使调用 UpdateWindow() 后绘制消息也会丢失?
我有一个具有以下窗口层次结构的应用程序:
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时如何解决闪烁问题?
谢谢,
I have an application with following windows hierarchy:
W1
-W2 (Child of W1)
- W3 ( Child of W2)
--------------------|
| W1|------------| |
| |W2 |------| | |
| | |W3 | | |
| | |------| | |
| |------------| |
|-------------------|
When certain event happens in W2, I call UpdateWindow
:
W2::onCertainEvent()
{
Invalidate(NULL);
UpdateWindow();
}
The OnPaint
handling of W2 looks like this:
W2::onPaint()
{
//W2 logic goes here
W3.Invalidate(NULL); //So that paint messages are given to W3
}
But some times the paint messages are getting lost in W2. Though UpdateWindow
gets called, there is no corresponding OnPaint
() getting called.
If I add a property WS_EX_TRANSPARENT
to W1 ( the parent of W2) then always paint messages are received @ W2.
But the problem with adding the WS_EX_TRANSPARENT
flag is that it creates lot of flicker when I resize the window W1.
My Questions are:
1. What is wrong in W2 so that Paint messages are lost?
2. Why adding WS_EX_TRANSPARENT
solves the Paint problem.
3. How do I solve flicker issue if the flag is used.
Thanks,
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
闪烁
可以通过处理 WM_ERASEBKGND 并确保它不执行任何操作来解决闪烁问题。可能会发生闪烁,因为每个窗口在每次绘制之前都会处理此消息,以使用其背景颜色擦除无效区域。如果您处理它并且不执行任何操作,则不会发生擦除 - 只需确保您的
WM_PAINT
处理程序绘制整个无效区域,否则您将留下先前绘制的痕迹。然而,在这种情况下,我相信会出现闪烁,因为每次绘制时 W1 首先绘制自身,然后是 W2,然后是 W3。这表明
WS_EX_TRANSPARENT
不是解决您遇到的问题的方法。缺少 WM_PAINT
很难知道如何追踪这一点。在 .NET 中,发生这种情况是因为子窗口遮盖了控件的整个客户区域,因此绘制消息不会传播,但我相信这是特定的 .NET 行为。如果您可以提供一个展示该问题的示例项目或示例代码,那将是一个很大的帮助。
同时,您可以删除 W3,以便 W2 不被遮挡,并查看是否所有绘制消息都返回。另请注意
CWnd::Invalidate
不接受 NULL 作为选项,它接受
BOOL
(TRUE
或FALSE
)。Flicker
Flicker can be resolved by handing
WM_ERASEBKGND
and making sure it does nothing. The flicker can occur because each Window handles this message before every paint to erase the invalid area using its background colour. If you handle it and do nothing, the erase doesn't occur - just make sure yourWM_PAINT
handler paints the entire invalidated area or you'll leave artifacts from the previous paint behind.However, in this case, I believe the flicker occurs because W1 paints itself first, then W2, then W3 on each paint. This suggests that
WS_EX_TRANSPARENT
is not the way to fix the problem you're experiencing.Missing WM_PAINT
It's difficult to know how to track this down. In .NET, this happens because the child windows obscure the entire client area of the control and so the paint message is not propagated through but I believe that's a specific .NET behaviour. If you could provide a sample project or sample code that exhibits the problem, it would be a big help.
In the meantime, you could remove W3 so that W2 is not obscured and see if all your paint messages return. Also, note that
CWnd::Invalidate
doesn't take NULL as an option, it takes aBOOL
(TRUE
orFALSE
).WM_PAINT“消息”并不是真正意义上的消息。它们的行为很像每个窗口消息队列末尾的标志。它们不经过线程消息队列,它们在windows消息队列中没有位置。当您尝试从 Windows 消息队列中检索消息并且没有其他消息时,就会生成它们。那时,所有不同的失效都会被考虑并生成一个或多个(!)WM_PAINT。
结果是,在
W2::onCertainEvent()
之后,将设置“窗口无效”标志。因此,最终将调用WM_PAINT
,但随后生成的 WM_PAINT 将不会专门用于该“特定事件”。历史背景是,如果有大量待处理的消息,您不想花费太多时间来绘制窗口,因为无论如何这些消息可能都会使您的窗口失效。最好先更新您的模型,然后再执行视图操作。
WM_PAINT "messages" are not really messages in the normal sense of the word. They behave much like flags at the end of the message queue of each window. They don't go through the thread message queue, they don't have a position in the windows message queue. They're generated when you try to retrieve a message from the windows message queue, and there are no other messages. At that time, all the different invalidations are considered and one or more (!) WM_PAINT are generated.
The result is that after your
W2::onCertainEvent()
the "window invalid" flag will be set. It follows that eventuallyWM_PAINT
will be called, but the WM_PAINT that is generated then will not be exclusively for that "Certain Event".The historical background is that you don't want to spend too much time painting a window if there were a lot of messages pending, as those are probably just going to invalidate your window anyway. Better get your Model up to date first, and then do the View stuff.