我的 MFC 应用程序有一个 CView 和几个浮动的非模态对话框。我目前正试图弄清楚为什么我的视图无效/重绘也会导致对话框被重绘。即使对话框不与视图重叠,也会发生这种情况。
有人知道如何调试/跟踪请求特定对话框重绘的人吗?拦截对话框上的 WM_PAINT 消息似乎为时已晚。
提前感谢您的帮助!
最好的祝愿,
费边
我的 MFC 应用程序有一个 CView 和几个浮动的非模态对话框。我目前正试图弄清楚为什么我的视图无效/重绘也会导致对话框被重绘。即使对话框不与视图重叠,也会发生这种情况。
有人知道如何调试/跟踪请求特定对话框重绘的人吗?拦截对话框上的 WM_PAINT 消息似乎为时已晚。
提前感谢您的帮助!
最好的祝愿,
费边
我认为您的非模态对话框是 WS_POPUP 窗口,对吗?(即它们是浮动窗口,可以出现在屏幕上的任何位置,而不仅仅是在您的应用程序窗口内。)。
如果它们是浮动窗口,那么从技术上讲,它们不是框架窗口的子窗口,但是文档倾向于在应该真正使用所有者的地方使用术语父级,因此很容易混淆。子窗口不能出现在其父窗口的客户区之外,拥有的窗口可以。每当其父窗口无效时,子窗口也将无效。但是拥有的窗口不会。
只有带有 WS_CHILD 样式标志的窗口可以是子窗口,否则它们是拥有的窗口。
如果这些是拥有的窗口,它们不会从您的主应用程序窗口继承失效,因此您需要在代码中查找调用 ::InvalidateRect() 的位置,其中第一个参数为 NULL 句柄。通常这是因为未初始化的变量。
当您调用::InvalidateRect(NULL, ...)
它时,它会告诉 Windows 使所有窗口无效。(它实际上告诉 Windows 使桌面窗口无效,它是所有窗口的父窗口)。使用 MFC,所有窗口的基类都有一个 InvalidateRect 方法,该方法转而调用 windows api,但使用当前对象的窗口句柄。作为一阶近似值,我认为您可以假设该窗口句柄将被正确初始化。您应该首先在自己的代码中查找调用。
获得 OnPaint 后,要知道失效请求的来源为时已晚。因此,为了找到这个错误,您将不得不检查您的代码或拦截InvalidateRect()
并在第一个参数中查找 NULL。
在一般情况下,这是一个困难的问题,因为有几种方法可以使窗口的全部或部分无效,并且头文件中的大量代码通过创建自动执行某些操作的此函数的变体来“帮助”您。
您可能会尝试在(位于 user32.dll 中)的顶部设置断点,InvalidateRect
并以第一个参数为空为条件。但根据调试器的设置方式,可能不允许您这样做。
您还可以尝试强制编译所有代码,以便通过您控制的函数重定向对 InvalidateRect 的调用。
// in some header file that gets included early by all of your code
#define InvalidateRect my_InvalidateRect
// in one of your .cpp files.
BOOL WINAPI my_InvalidateRect(HWND hwnd, CONST RECT *prc, BOOL bErase)
{
#undef InvalidateRect
assert(hwnd != NULL);
InvalidateRect(hwnd, prc, bErase);
#define InvalidateRect my_InvalidateRect
};
如果没有找到它,然后做同样的InvalidateRgn
事情RedrawWindow
这些类型的错误很难找到。我不羡慕你。在我自己的代码中,我永久禁止直接调用 InvalidateRect,它们必须始终通过包装函数,以便我始终可以在调试版本中检查 NULL 窗口句柄。但话又说回来,我不使用 MFC,所以执行这种策略更容易。
我会以与在 MFC 中调试我不太了解的任何内容相同的方式执行此操作——我尝试通过在全新项目中重现行为来隔离问题。
因此,制作一个全新的 MFC 应用程序,向其中添加一个无模式对话框,在您的 CView 上调用 Invalidate 并查看它是否仍然出现。
如果它仍然发生,那么它必须是您的大型机发送该绘制消息。因此,您可以尝试在大型机的 PreTranslateMessage 中捕获它。
如果它没有发生,那么您在应用程序中所做的某些事情会导致它。如果是这样,您可以尝试通过消除应用程序中的复杂性来解决您所做的事情,直到找到导致它不再发生的事情。
对话框也收到 WM_PAINT 消息的原因是它们是 Karim 已经建议的 CView 的子窗口。
最有可能发生的情况是,在导致视图重绘的失效之后,一条WM_PAINT
消息被发送到此窗口,并且此窗口的标准 OnPaint() 处理程序(CWnd 的成员)将WM_PAINT
消息发送到其子窗口(对话框)。
WM_PAINT 消息本身由 windows 发送,以响应对 或 的调用UpdateWindow()
,RedrawWindow()
请参阅MSDN
WM_PAINT 消息由系统生成,不应由应用程序发送。
最接近消息处理机制背后的场景是覆盖从 CWnd 派生的 CView 类的 WindowProc。这是接收 WM_PAINT 和任何其他消息的回调。
干杯霍尔格
看看这个:
http://msdn.microsoft.com/en-us/library/01c9aaty(VS.80).aspx
您可能会覆盖 OnPaint 并找出消息的来源......
编辑:
当 Windows 或应用程序请求重绘应用程序窗口的一部分时,框架调用此成员函数。
因此,要么是操作系统请求您重绘,要么是在您的应用程序中完成。
也看看这个论坛线程的第一个答案:http: //social.msdn.microsoft.com/Forums/en/vcgeneral/thread/3f53fce3-38dd-441b-b112-82eff4dafc9e