Tag Archives: Feature Pack

Custom Paint in MDI Client

In some MDI applications, would be nice to perform some custom painting the MDI Client area. For example we can fill the background with a brush or draw a logo image. One classic and well known method is to subclass the MDI Client window in our own class derived from CWnd MFC class. After subclassing, all we have to do is to handle WM_PAINT and/or WM_ERASEBKGND and perform our custom painting. There are tens of articles describing this method in detail, and you cand find some by clicking the links shown in the bottom of this article.

That works great if the main frame class is derived from CMDIFrameWnd, but it’s no more possible if the main frame class is derived from CMDIFrameWndEx (shipped with Visual Studio 2008 with Feature Pack and newer Visual Studio versions). That’s because CMDIFrameWndEx subclases the MDI Client window, itself (see CMDIFrameWndEx::m_wndClientArea of type CMDIClientAreaWnd). MFC, adds the subclassed window in a permanent map and does not allow subclassing twice. One can say “well, just set CMDIFrameWndEx::m_bDoSubclass to FALSE before calling CMDIFrameWndEx::OnCreateClient; next we can do subclassing as we wish”. That doesn’t work either, because in many places the framework expects using exactly CMDIFrameWndEx::m_wndClientArea and nothing else.

Searching for a solution

In an older discussion about a related subject, Joseph M. Newcomer proposed a simple trick: temporarily attach the MDI Client window handle to your own class, whenever it’s necessary to force  repainting the MDI Client area.

void CMyApp::RedrawClientArea()
{
CMySublcass w;
w.Attach(m_wndClientArea.Detach());
w->Invalidate();
w->UpdateWindow();
m_wndClientArea.Attach(w.Detach());
}

Next, just have to call CMyApp::RedrawClientArea in our MFC application, where necessary. That’s IMO very ingenious and should work but, as the author states himself, it’s “remarkably ugly”. So I spent some time  trying other tricks, which included the “hacking” of application thread maps. None was useful.

The right solution

Finally, I found the better solution. It is incredible simple: just have to override CMDIFrameWndEx::OnEraseMDIClientBackground virtual function!
Here is an example that fills the MDI Client area using a given brush.

Demo project

The demo project, attached here, is an MDI MFC application that paints in the MDI Client a custom background and a logo image.

Custom Paint in MDI Client - Demo

Custom Paint in MDI Client – Demo

 

Resources

See also

Downloads