Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Making the SDI view smaller than the CFrameWnd

0.00/5 (No votes)
31 Mar 2006 1  
This article describves a technique for making an SDI view smaller than its parent frame.

Introduction

I have seen this problem posted on the MFC newsgroup a few times, so I thought that it would be a good idea to post a solution here. The question is "How do I make an SDI view smaller than its parent frame window?". The quick answer is, catch the WM_SIZE message in the CFrameWnd and resize the view accordingly. But there is a catch, and it's called flicker!

What happens is that when the view is resized, parts of the frame window around the view is suddenly exposed. CFrameWnd, by default, does not erase its background, so there will be a lot of junk left over on the screen. To fix this, WM_ERASEBKGND must be handled in CFrameWnd in order to fill that area.

Wait, there is more. CFrameWnd::OnSize(...), by default, fills its entire client area with the view. That is done in the CFrameWnd::RecalcLayout() method. This means that CFrameWnd::OnSize can't be called. This, in turn, causes another problem, and that is the toolbar and status bar will no longer be resized after the frame is resized.

So, what's the solution already?

The solution comes in three parts:

First, WS_CLIPCHILDREN must be added to the frame window. That should be done in the CMainFrame::PreCreateWindow() method override.

BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
   cs.style |= WS_CLIPCHILDREN;

   if( !CFrameWnd::PreCreateWindow(cs) )
      return FALSE;

   return TRUE;
}

Next, the background has to be painted. This can be done by handling the WM_ERASEBKGND message for the frame window.

BOOL CMainFrame::OnEraseBkgnd(CDC* pDC)
{
   CRect Rect;
   GetClientRect(&Rect);
   pDC->FillSolidRect(&Rect,::GetSysColor(COLOR_APPWORKSPACE));

   return TRUE;
}

Last but not least, we have to handle the frame window's resizing. This involves a couple of little tricky moves.

void CMainFrame::OnSize(UINT nType, int cx, int cy)
{
   m_nIdleFlags &= ~idleLayout;
   CWnd::OnSize(nType,cx,cy);
   m_bInRecalcLayout = TRUE;
   RepositionBars(0, 0xffff, 0, reposExtra, &m_rectBorder);
   m_bInRecalcLayout = FALSE;

   if (GetActiveView() != NULL)
   {
      CRect Rect;
      GetClientRect(Rect);
      GetActiveView()->SetWindowPos(NULL,Rect.left + 
                          100,Rect.top + 100,Rect.Width()-200,
                          Rect.Height()-200,SWP_SHOWWINDOW);
   }
}

The first line of the function is clearing the idelLayout flag from the m_nIdleFlags variable. The frame window is constantly updating the UI elements such as toolbars during idle processing. One other thing that the frame window does during this time is to call RecalcLayout, which as you already know will resize the view. Removing the idleLayout flag will prevent the OnIdleUpdateCmdUI method from resizing the view.

The next call is to CWnd::OnSize. Since CFrameWnd::OnSize is not being called, its parent's OnSize must be called in case CWnd does something important.

Now comes the part where the toolbar and the statusbar have to be repositioned. The member variable m_bInRecalcLayout is a CFrameWnd internal variable that keeps the RecalcLayout from reentering itself. That flag is set to TRUE in case the call to RepositionBars triggers something that would call RecalcLayout. Don't forget to set it back to FALSE. Next is the call to RepositionBars. The only difference between this call to RepositionBars and the one inside RecalcLayout is the third parameter. The third parameter is called nIDLeftOver which is the "ID of the pane that fills the rest of the client area". CFrameWnd passes the ID of the view as this parameter, and since the view should not fill the frame, a 0 must be passed instead.

And finally, for the moment we have all been waiting for, resize the view to be smaller than the frame window. The code above simply makes the view smaller by 100 pixels from each side. But the possibilities are endless.

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