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.
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.
BOOL CMainFrame::OnEraseMDIClientBackground(CDC* pDC)
// paint MDI Client background
CBrush* pOldBrush = pDC->SelectObject(&m_brushMDIBack);
pDC->PatBlt(0, 0, rcClient.right, rcClient.bottom, PATCOPY);
// free GDI objects
return TRUE; // no further default processing
The demo project, attached here, is an MDI MFC application that paints in the MDI Client a custom background and a logo image.
- Codeguru Forums: How to change the background of the MDI main frame?
- Codexpert Forums (RO): Cum punem o imagine in zona MDI client?
- MSGROUPS.NET: How to subclass an MFC window?
- MSDN Forums: Painting the mainframe client area
- Silviu Marius Ardelean’s blog: SubclassWindow() method issues in projects base on MFC Feature Pack
- Custom Paint in MDI Client (1261) – demo project