Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / MFC

Change the background color of the frame area of an MDI application.

4.93/5 (29 votes)
12 Apr 20072 min read 1   898  
This article describes how to change the color of Frame Windows client area by subclassing the control which draws the background.

Screenshot - MDIFrameBackground.jpg

Introduction

This is actually a very simple task. The hard thing to figure out is the fact that the background part of the main frame Window isn't really handled by the frame Window itself. It contains another Window that fills the area inside the frames border. This Window is known as m_hWndMDIClient.

Background

To get this task done, my first instinct was to catch the WM_ERASEBKGND in CMainFrame and do the FillSolidRect there. But I soon realized that approach didn't do anything other than make the frame flicker and show red only when it's being resized, otherwise the gray background was completely intact. Not exactly what I was looking for. Suddenly it became a little mystery. Why doesn't the background of the frame change when I fill it with a color in the frame's WM_ERASEBKGND handler? So I went on a hunt, I went through a lot of the CMDIFrameWnd and CFrameWnd code looking for methods that would draw on the frame, and there was not much there. I finally ended up at CMainFrame::OnCreate method, I set a breakpoint and stepped through the CMDIFrameWnd::OnCreate method. After what seemed to be hours of searching I came across the following code in CMDIFrameWnd::CreateClient:

C++
// Create MDICLIENT control with special IDC
if ((m_hWndMDIClient = ::CreateWindowEx(dwExStyle, _T("mdiclient"), NULL,
          dwStyle, 0, 0, 0, 0, m_hWnd, (HMENU)AFX_IDW_PANE_FIRST,
          AfxGetInstanceHandle(), (LPVOID)&ccs)) == NULL)
{
   TRACE(traceAppMsg, 0, _T("Warning: CMDIFrameWnd::OnCreateClient: 
                                             failed to create MDICLIENT.")
            _T(" GetLastError returns 0x%8.8X\n"), ::GetLastError());
   return FALSE;
}

It is pretty clear that the frame Window is creating another Window to act as its center (To this day I don't really know the purpose behind this). So that's where this code comes in. By subclassing the client Window m_hWndMDIClient I was able to cleanly change the color of the MDI frame Window.

Using the code

To change the color of the background, first we must create a new CWnd derived class which handles the WM_ERASEBKGND message and fills the client area of the Window with a different color. So let's add a class called CClientWnd which inherits from CWnd:

C++
#pragma once

// CClientWnd
class CClientWnd : public CWnd
{
   DECLARE_DYNAMIC(CClientWnd)
public:

   CClientWnd();
   virtual ~CClientWnd();

protected:

   afx_msg BOOL OnEraseBkgnd(CDC* pDC);
   DECLARE_MESSAGE_MAP()
};

And implement the OnEraseBkgnd method:

C++
// ClientWnd.cpp : implementation file

#include "stdafx.h"
#include "ClientWnd.h"

// CClientWnd

IMPLEMENT_DYNAMIC(CClientWnd, CWnd)

CClientWnd::CClientWnd()
{
}

CClientWnd::~CClientWnd()
{
}

BEGIN_MESSAGE_MAP(CClientWnd, CWnd)
   ON_WM_ERASEBKGND()
END_MESSAGE_MAP()

// CClientWnd message handlers
BOOL CClientWnd::OnEraseBkgnd(CDC* pDC)
{
   CRect Rect;
   GetClientRect(&Rect);

   //fill the entire client area with Red!
   pDC->FillSolidRect(&Rect,RGB(255,0,0));

   //return TRUE to indicate that we took care of the erasing
   return TRUE;
}

Now the only thing left to do is to subclass the Window m_hWndMDIClient. To do that we are going to overwrite CMainFrame::OnCreateClient method, and declare m_Client in CMainFrame's class declaration as a private variable.

C++
class CMainFrame : public CMDIFrameWnd
{
......
protected:
   virtual BOOL OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext);

private:
   CClientWnd   m_Client;
};

Implementation of OnCreateClient should look like this:

C++
BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
{
   if (CMDIFrameWnd::OnCreateClient(lpcs, pContext))
   {
      m_Client.SubclassWindow(m_hWndMDIClient);
      return TRUE;
   }

   return FALSE;
}

Have fun!

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here