Click here to Skip to main content
15,880,405 members
Articles / Desktop Programming / MFC
Article

Making the SDI view smaller than the CFrameWnd

Rate me:
Please Sign up or sign in to vote.
4.07/5 (9 votes)
31 Mar 20063 min read 51.4K   681   25   6
This article describves a technique for making an SDI view smaller than its parent frame.

Image 1

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


Written By
Architect
United States United States
Ali Rafiee has been developing windows applications using C++ since 1991, and he hasn't looked back since. Ali has been a software development consultant for must of his career, but he has finally settled down and has been working for an educational software company since 2000. While he is not working, he is either learning C#, flying airplanes, playing with his daughter, or answering peoples question on newsgroups, he finds that to be a great learning tool for himself.

Ali is also a Microsoft Visual C++ MVP.

Comments and Discussions

 
QuestionYou are wrong... Pin
bidanjun16-Jul-14 21:09
bidanjun16-Jul-14 21:09 
GeneralToo complex. Here is a simple solution. Pin
the_gurudev3-Apr-06 23:04
the_gurudev3-Apr-06 23:04 
AnswerRe: Too complex. Here is a simple solution. Pin
Ali Rafiee4-Apr-06 5:37
Ali Rafiee4-Apr-06 5:37 
GeneralRe: Too complex. Here is a simple solution. Pin
the_gurudev4-Apr-06 11:59
the_gurudev4-Apr-06 11:59 
GeneralRe: Too complex. Here is a simple solution. Pin
Hunt Chang18-Jan-08 7:27
Hunt Chang18-Jan-08 7:27 
GeneralRe: Too complex. Here is a simple solution. Pin
bidanjun16-Jul-14 21:12
bidanjun16-Jul-14 21:12 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.