Home
Fractals
Tutorials
Books
My blog
My LinkedIn Profile

BOOKS i'm reading

Napoleon Hill Keys to Success: The 17 Principles of Personal Achievement, Napoleon Hill, ISBN: 978-0452272811
The 4-Hour Workweek: Escape 9-5, Live Anywhere, and Join the New Rich (Expanded and Updated), Timothy Ferriss, ISBN: 978-0307465351
The Fountainhead, Ayn Rand, ISBN: 0452273331

Control Client area minimum size (WM_GETMINMAXINFO) with MFC in C++

Olivier Langlois, IT superstar coach, Dominate LinkedIn Formula author
by Olivier Langlois

C++ demo to control the control area minimum size in MFC with WM_GETMINMAXINFO

Contents





Introduction

Isn't it strange that sometimes, even problems that seem easy at first are the ones causing the most troubles to find a solution to them? Trying to restrict a client view to a minimum size is one of those problems. I have tried many approaches before reaching a satisfactory solution. The final solution is still not perfect and I will explain why later. In this C++ Windows programming tutorial, I will give some background on the problem and describe the various difficulties that I have encountered on the road by presenting my first attempts to solve the problem. Then I will present the inner working of the final solution and give insights on why it has been designed like it is. I will then continue by presenting the demo program whose purpose is to show how to use the code in your own programs and finally, I will discuss the limitations and the possible enhancement to the current code.

Background

The first nave attempt I tried was to handle the WM_GETMINMAXINFO message directly in the child view class and it looked like this:

void CChildView::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI)
{
    lpMMI->ptMinTrackSize.x = DEFAULTMINCLIENTSIZE;
    lpMMI->ptMinTrackSize.y = DEFAULTMINCLIENTSIZE;
}

If only it was that simple! It does not work at all because only resizable top most windows receive the WM_GETMINMAXINFO message and CChildView is not such a window. This is the first difficulty to solve the problem. The second difficulty to solve this problem with MFC is that MFC split the frame client area among different UI components (views, status bar and the toolbars) and most of the management of that area is done by MFC under the hood and is practically not documented. My second attempt tried to workaround that difficulty and it looked like this:

CMainFrame::CMainFrame()
{
    minX = DEFAULTMINCLIENTSIZE;
    minY = DEFAULTMINCLIENTSIZE;
}

void CMainFrame::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI)
{
    CView *pView = GetActiveView();
    if( pView )
    {
        RECT viewRect;
        pView->GetClientRect(&viewRect);
        if( viewRect.right < DEFAULTMINCLIENTSIZE )
        {
            minX += (DEFAULTMINCLIENTSIZE - viewRect.right);
        }
        if( viewRect.bottom < DEFAULTMINCLIENTSIZE )
        {
            minY += (DEFAULTMINCLIENTSIZE - viewRect.bottom);
        }

    }
    lpMMI->ptMinTrackSize.x = minX;
    lpMMI->ptMinTrackSize.y = minY;
}

It gives a descent result but it is not very accurate. For instance, with an application having a toolbar and a status bar, if you were to reduce the vertical size of the frame, it would go a little below DEFAULTMINCLIENTSIZE and them snaps back to the specified minimum height. Also, if you were to remove the status bar and the toolbar after reaching the minimum size you would find that the window refuse to minimize further even if the view size is above the specified minimum size. After that second attempt, I searched a little bit on the net to see what solutions others have come up with the same problem. I found one article from ovidiucucu and he propose the following code for the problem that I am having:

void CChildFrame::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI)
{
  // the minimum client rectangle (in that is lying the view window)
  CRect rc(0, 0, 200, 150);
  // compute the required size of the frame window rectangle
  // based on the desired client-rectangle size
  CalcWindowRect(rc);

  lpMMI->ptMinTrackSize.x = rc.Width();
  lpMMI->ptMinTrackSize.y = rc.Height();
}

It sounds good but it does not work neither. As I previously said, the frame client rectangle is shared among the status bar, the toolbars and the view. So if your frame client area only has a view, it will work otherwise it will not. Now with these different attempts, it should start to become clear that the only way to solve this problem is to put our hands in MFC guts to be able to exactly keep track of every client area components size and position. This is exactly what my code is doing and I will show you how in the next section.





Page 1 2 3

Home :: Fractals :: Tutorials :: Books :: My blog :: My LinkedIn Profile :: Contact