# CodeGuru Technical FAQs > CodeGuru Individual FAQs >  MFC MDI: How to change the background of the MDI main frame?

## ovidiucucu

*Q:* How can I change the background of the MDI main frame? 

*A:* In fact, on the main frame background lies another window of 'MDIClient' class. So do the following:

Using ClassWizard, add a generic CWnd-derived class, let's say it CMDIClientWnd
Add a member of type CMDIClientWnd to CMainFrame class



```
class CMainFrame : public CMDIFrameWnd
{
// ...
// Attributes
protected:
   CMDIClientWnd m_wndMDIClient;
// ...
};
```

 In CMainFrame::OnCreate subclass the MDI client window



```
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
   if (CMDIFrameWnd::OnCreate(lpCreateStruct) == -1)
      return -1;
   // NOTE: m_hWndMDIClient is a public member of CMDIFrameWnd
   m_wndMDIClient.SubclassWindow(m_hWndMDIClient);
// ...
}
```

 Add a member of type CBrush to class CMDIClientWnd



```
class CMDIClientWnd : public CWnd
{
// Attributes
protected:
   CBrush  m_brush; // will be used to fill the backgound
};
```

 Create the brush in CMDIClientWnd constructor



```
CMDIClientWnd::CMDIClientWnd()
{
   // this example uses a pattern brush filled from a bitmap resource
   CBitmap bitmap;
   bitmap.LoadBitmap(IDB_FISHING);
   m_brush.CreatePatternBrush(&bitmap);
}
```

 Finally, handle 'WM_ERASEBKGND'



```
BOOL CMDIClientWnd::OnEraseBkgnd(CDC* pDC) 
{
   CBrush* pbrushOld = pDC->SelectObject(&m_brush);
   CRect rect;
   pDC->GetClipBox(&rect);
   pDC->PatBlt(rect.left, rect.top, rect.Width(), rect.Height(), PATCOPY);
   pDC->SelectObject(pbrushOld);

   return TRUE;
}
```

----------


## ovidiucucu

*Q:* I have changed the MDI client background like in example shown above. Next, I have tried to draw a centered bitmap image, but encountered a strange behavior when resizing the frame window: the image is not entirely drawn or appears multiplied. I have tried both in 'WM_ERASEBKGND' and 'WM_PAINT' message handlers but without success. What I'm missing?

*A:* That happens because 'MDIClient' window class has not 'CS_VREDRAW' and 'CS_HREDRAW' styles (if 'CS_VREDRAW' and 'CS_HREDRAW' are set, the entire window is redrawn if a movement or size adjustment changes the width of the client area). 

You can fix the problem by invalidate the client area in the 'WM_SIZE' message handler:



```
void CMDIClientWnd::OnSize(UINT nType, int cx, int cy) 
{
   CWnd::OnSize(nType, cx, cy);
   Invalidate(FALSE);
}

void CMDIClientWnd::OnPaint() 
{
   CPaintDC dc(this); // device context for painting

   CDC dcMem;
   dcMem.CreateCompatibleDC(&dc);
   CBitmap bitmap;
   bitmap.LoadBitmap(IDB_LOGO);
   CBitmap* pOldBitmap = dcMem.SelectObject(&bitmap);

   BITMAP bmp;
   bitmap.GetBitmap(&bmp);
   CRect rc;
   GetClientRect(rc);
   const int nWidth  = bmp.bmWidth;
   const int nHeight = bmp.bmHeight;
   const int x       = (rc.Width() / 2) - (nWidth / 2);
   const int y       = (rc.Height() / 2) - (nHeight / 2);

   dc.BitBlt(x, y, nWidth, nHeight, &dcMem, 0, 0, SRCCOPY);  

   dcMem.SelectObject(pOldBitmap);
}
```

*Q:* The centered bitmap drawn as in previous example flickers when resizing the frame window. Can be this avoided?

*A:* Yes. 

In 'WM_ERASEBKGND' do nothing, just return 'FALSE'



```
BOOL CMDIClientWnd::OnEraseBkgnd(CDC* pDC) 
{
   // All drawing moved in OnPaint
   return FALSE;
}
```

Perform all drawing (including filling with the brush) in WM_PAINT mesage handler using 'double buffering', i.e. draw in an additional memory device context, then copy the memory device context contents in the client device context.



```
void CMDIClientWnd::OnPaint() 
{
   CPaintDC dc(this);
   CRect rcClient;
   GetClientRect(rcClient);

   CDC dcMem1; // memory DC for double buffering
   dcMem1.CreateCompatibleDC(&dc);
   CBitmap bitmap1;
   bitmap1.CreateCompatibleBitmap(&dc, rcClient.Width(), rcClient.Height());
   CBitmap* pOldBitmap1 = dcMem1.SelectObject(&bitmap1);
   // fill memory device context with the desired brush
   dcMem1.FillRect(rcClient, &m_brush);

   CDC dcMem2; // memory DC for the bitmap to draw
   dcMem2.CreateCompatibleDC(&dc);
   CBitmap bitmap2;
   bitmap2.LoadBitmap(IDB_LOGO);
   CBitmap* pOldBitmap2 = dcMem2.SelectObject(&bitmap2);

   BITMAP bmp;
   bitmap2.GetBitmap(&bmp);
   int nWidth  = bmp.bmWidth;
   int nHeight = bmp.bmHeight;
   int x       = (rcClient.Width() / 2) - (nWidth / 2);
   int y       = (rcClient.Height() / 2) - (nHeight / 2);
   // copy the bitmap in memory device context 
   dcMem1.BitBlt(x, y, nWidth, nHeight, &dcMem2, 0, 0, SRCCOPY);

   CRect rcClip;
   dc.GetClipBox(rcClip);

   nWidth  = rcClip.Width();
   nHeight = rcClip.Height();
   x       = rcClip.left;
   y       = rcClip.top;
   // copy memory device context in client device context
   dc.BitBlt(x, y, nWidth, nHeight, &dcMem1, x, y, SRCCOPY); 

   dcMem1.SelectObject(pOldBitmap1);
   dcMem2.SelectObject(pOldBitmap2);
}
```



See also
A Custom MDI Client Class.

----------


## ovidiucucu

If the main frame class is derived from *CMDIFrameWndEx* (Visual Studio 2008 and newer), the solution is much simpler: just override *CMDIFrameWndEx::OnEraseMDIClientBackground*.   

Example


```
BOOL CMainFrame::OnEraseMDIClientBackground(CDC* pDC)
{
   CRect rc;
   GetClientRect(rc);

   // fill the MDI client background 
   CBrush* pbrushOld = pDC->SelectObject(&m_brush);
   pDC->PatBlt(rc.left, rc.top, rc.Width(), rc.Height(), PATCOPY);

   // may perform more painting here...

   // free the GDI objects
   pDC->SelectObject(pbrushOld);

   return TRUE; // returns TRUE for no further default processing
}
```

See also
Custom Paint in MDI ClientCMDIFrameWndEx::OnEraseMDIClientBackground

----------

