-
November 28th, 2004, 12:30 PM
#1
MFC MDI: How to change the background of the MDI main frame?
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
Code:
class CMainFrame : public CMDIFrameWnd
{
// ...
// Attributes
protected:
CMDIClientWnd m_wndMDIClient;
// ...
};
- In CMainFrame::OnCreate subclass the MDI client window
Code:
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
Code:
class CMDIClientWnd : public CWnd
{
// Attributes
protected:
CBrush m_brush; // will be used to fill the backgound
};
- Create the brush in CMDIClientWnd constructor
Code:
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'
Code:
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;
}
Last edited by Andreas Masur; July 25th, 2005 at 04:07 PM.
-
June 7th, 2005, 09:19 AM
#2
MFC MDI: How to change the background of the MDI main frame? (2)
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:
Code:
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'
Code:
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.
Code:
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
Last edited by ovidiucucu; January 29th, 2013 at 11:51 AM.
-
January 29th, 2013, 11:43 AM
#3
MFC MDI: How to change the background of the MDI main frame? (3)
If the main frame class is derived from CMDIFrameWndEx (Visual Studio 2008 and newer), the solution is much simpler: just override CMDIFrameWndEx::OnEraseMDIClientBackground.
Example
Code:
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
Tags for this Thread
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|