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






4.93/5 (27 votes)
Apr 12, 2007
2 min read

82697

898
This article describes how to change the color of Frame Windows client area by subclassing the control which draws the background.
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
:
// 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
:
#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:
// 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.
class CMainFrame : public CMDIFrameWnd
{
......
protected:
virtual BOOL OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext);
private:
CClientWnd m_Client;
};
Implementation of OnCreateClient
should look like this:
BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
{
if (CMDIFrameWnd::OnCreateClient(lpcs, pContext))
{
m_Client.SubclassWindow(m_hWndMDIClient);
return TRUE;
}
return FALSE;
}
Have fun!