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

Automatic Resizing of a FormView Based Application When the User Toggles the Control Bars On or Off

0.00/5 (No votes)
26 Feb 2004 1  
Explains how to implement an application which automatically resizes itself when the user toggles the control bars on or off.

Figure 1: The application window fits the whole client window exactly plus a statusbar and some toolbars.

Figure 2: One of the toolbars is docked to the side, one floating and the statusbar is removed. The application window is resized automatically to still just fit the client window.

Introduction

I created a SDI application where I put all the controls on the view, having it derived from CFormView. The application also had a couple of controlbars, like a statusbar and a few dockable toolbars. When the application started, I had the view and the parent frame resized to snugly fit my controls on it. However, when a user would toggle on or off my toolbars or the statusbar, the size of the frame window, it was either too big or too small to display the view. All my hard work with resizing the application is wasted. So I added some code, so my CMainFrame class could resize itself whenever the user toggled on or off the controlbars to fit the view. Not very complicated, but it took me some time to figure out how to do it most effectively.

Details

Below are the steps to create a CMainFrame class with automatic resizing. See also attached source code for a full demo application and more explanations.

  1. Create a Single Doc Application with a view derived from CFormView.
  2. Using Class Wizard, for MainFrame, add a message handler for the message called RecalcLayout.
  3. Add private int members called m_nControlBarsWidth and m_nControlBarsHeight in the CMainFrame class and initialize them to 0 in the constructor.
  4. Add a private bool member called m_bCtrlBarsChanged in the CMainFrame class and initialize it to false in the constructor.
  5. Change the implementation of CMainFrame::RecalcLayout to the following:
    void CMainFrame::RecalcLayout(BOOL bNotify) 
    {
        // RecalcLayout is called by MFC when the frame window is resized. 
        // In this implementation of RecalcLayout, the application  
        // call SetWindowPos, which will resize the frame window.
        // Therefore, if RecalcLayout is called because 
        // the application is resizing the frame we want to ignore that call.
        // We use m_bCtrlBarsChanged to keep track if the application are  
        // resizing the frame window because the user toggled the controlbars  
        // on or off or if the user is resizing the window.
    
        if (m_bCtrlBarsChanged)
        { 
            // Ignore call since it's triggered by our call to SetWindowPos. 
            // Otherwise we will end up looping.
    
            return;
        }
    
        if (!IsIconic() && !IsZoomed())
        {
            // Calculate size of controlbars (statusbar and toolbars).  
            // We should only do this when the window is not maximized 
            // or minimized. When maximized we should not change
            // the window's size, it should stay maximized. I don't think this 
            // function can be called when window is minimized,
            // but if so then window size
            // should not be changed either.
    
            int nControlBarsHeightCurrent = 0;
            int nControlBarsWidthCurrent = 0;
    
            // Calculate the current total height and width of our controlbars.
            // We only care of a controlbar's height or width
            // depending on how it is docked.
    
            // We will use CWnd::RepositionBars() with
            // the reposQuery parameter to get 
            // measurements of our controlbars. 
    
            // A statusbar is always docked to bottom so only
            // height of statusbar is interesting.
    
            CRect rectControlBar;
    
            RepositionBars(AFX_IDW_STATUS_BAR, AFX_IDW_STATUS_BAR, 
               AFX_IDW_PANE_FIRST, reposQuery, &rectControlBar, NULL, FALSE);
            nControlBarsHeightCurrent += rectControlBar.Height();
    
            // Toolbars can be docked to any side of the frame so
            // depending on if a toolbar is added to the top or bottom
            // or if docked to left or right side, we need to 
            // add check its height or width.
    
            RepositionBars(AFX_IDW_DOCKBAR_TOP, AFX_IDW_DOCKBAR_TOP, 
               AFX_IDW_PANE_FIRST, reposQuery, &rectControlBar, NULL, FALSE);
            nControlBarsHeightCurrent += rectControlBar.Height();
    
            RepositionBars(AFX_IDW_DOCKBAR_BOTTOM, AFX_IDW_DOCKBAR_BOTTOM, 
               AFX_IDW_PANE_FIRST, reposQuery, &rectControlBar, NULL, FALSE);
            nControlBarsHeightCurrent += rectControlBar.Height();
    
            RepositionBars(AFX_IDW_DOCKBAR_LEFT, AFX_IDW_DOCKBAR_LEFT, 
               AFX_IDW_PANE_FIRST, reposQuery, &rectControlBar, NULL, FALSE);
            nControlBarsWidthCurrent += rectControlBar.Width();
    
            RepositionBars(AFX_IDW_DOCKBAR_RIGHT, AFX_IDW_DOCKBAR_RIGHT, 
               AFX_IDW_PANE_FIRST, reposQuery, &rectControlBar, NULL, FALSE);
            nControlBarsWidthCurrent += rectControlBar.Width(); 
    
            if (nControlBarsHeightCurrent != m_nControlBarsHeight || 
                nControlBarsWidthCurrent != m_nControlBarsWidth)
            {
                // The size of the controlbars have changed.
                // Lets resize the frame window 
                // to accommodate this change. The goal is to keep
                // the client window unchanged
                // and resize the frame instead.
    
                // Set m_bCtrlBarsChanged to true so we know
                // the application is resizing the 
                // dialog, not the user.
    
                m_bCtrlBarsChanged = true;
    
                // nControlBarsWidthCurrent - m_nControlBarsWidth
                // is how much the bars have 
                // changed in width and that is how much
                // the frame's width should be adjusted.
                // The calculations for height is similar.
    
                // Get the current size of the frame window.
    
                CRect rectFrame;
                GetWindowRect(rectFrame);
    
                // Adjust the size of the frame window. 
    
                SetWindowPos(NULL, 0, 0, 
                  rectFrame.Width() + 
                  nControlBarsWidthCurrent - m_nControlBarsWidth, 
                  rectFrame.Height() + 
                  nControlBarsHeightCurrent - m_nControlBarsHeight,
                  SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
    
                // Save the size of the controlbars for next time
                // the user toggles the controlbars 
                // on or off so we know how much we should
                // adjust the size of the frame.
    
                m_nControlBarsWidth = nControlBarsWidthCurrent;
                m_nControlBarsHeight = nControlBarsHeightCurrent;
    
                // The application is finished resizing the dialog.
    
                m_bCtrlBarsChanged = false;
            }
        }
    
        CFrameWnd::RecalcLayout(bNotify);
    }

Comments

CWnd::RepositionBars() is used to calculate the width and height of the different bars. It needs to be called differently depending on how our controlbars are docked.

If you want to add support for CMainFrame::OnGetMinMaxInfo (message handler for WM_GETMINMAXINFO), you need to do some extra coding, since the min size must also be updated when the user toggles control bars on or off. See the source code for how this is implemented.

Article History

The original article was posted on 28th January, 2002. This update is done to fix a bug when the window was maximized and to handle several toolbars. Also, side docking was not handled before. I added another picture to better show the code in action.

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