Issue
This article illustrates how to fix a common flicker problem in MDI applications when you create or activate an MDI child and an application is in maximized state. You catch a glimpse of the new activated MDI child shown at the picture above.
To reproduce the problem:
- Create a new MFC MDI application project.
- Run and maximize the application.
- In maximized state, create a few MDI children and try switching between them.
When you create a new or activate an inactive window, you will see the flicker.
Workaround
The solution to the problem is very simple. The flicker comes from drawing the caption, the frame and the client area of the restored MDI child. To eliminate it, override "WindowProc" in your class derived from CMDIChildWnd
. For the non-client area, filter WM_NCPAINT
message, and for the client area, handle WM_SIZE
message like this:
if(message==WM_SIZE)
{
if(wParam==SIZE_MAXIMIZED && pChildFrame==this)
return CMDIChildWnd::WindowProc(message, wParam, lParam);
SetRedraw(FALSE);
LRESULT ret = CMDIChildWnd::WindowProc(message,
wParam, lParam);
SetRedraw();
return ret;
}
In the previous version of this article I also filtered message 174
. Ignoring this message prevents drawing non-themed caption buttons. The picture of the buttons looks like this:
This message is also sent when a window is restored. Now drawing for restored windows is disabled, so we don't need "message==174
" in the "if
" statement anymore.
I have also added if(message==WM_NCPAINT || message==WM_SIZE)
as a first line in the window procedure. It prevents from assertion in objcore.cpp (AfxAssertValidObject
) when you try to close the MDI child, the view is derived from CHtmlView
and the active configuration is "Debug".
So the workaround code looks like this:
LRESULT CChildFrame::WindowProc(UINT message,
WPARAM wParam, LPARAM lParam)
{
if(message==WM_NCPAINT || message==WM_SIZE)
{
BOOL bMax;
CMDIFrameWnd* pParentFrame = (CMDIFrameWnd*)GetParentFrame();
if(pParentFrame)
{
CMDIChildWnd* pChildFrame = pParentFrame->MDIGetActive(&bMax);
if(bMax)
{
if(message==WM_NCPAINT)
return 0;
if(message==WM_SIZE)
{
if(wParam==SIZE_MAXIMIZED &&
pChildFrame==this)
return CMDIChildWnd::WindowProc(message, wParam, lParam);
SetRedraw(FALSE);
LRESULT ret =
CMDIChildWnd::WindowProc(message, wParam, lParam);
SetRedraw();
return ret;
}
}
}
}
return CMDIChildWnd::WindowProc(message, wParam, lParam);
}
A demo application
Check/uncheck the "FIX" button to enable/disable the fix code.