Minimum size splitter

For my latest project we needed splitter panes that had proper minimum sizes, in that the user couldn't physically resize the splitter pane smaller than a specified amount. The standard MFC splitter class allows you to set minimum sizes, but these only affect what is displayed, not how small the panes can be. CMinSplitterWnd is a drop-in replacement for (and is derived from) CSplitterWnd.

Instructions:

  1. Add MinSplitterWnd.cpp and MinSplitterWnd.h to your current project (e.g. Menu Project->Add to project->Add files).
  2. Where you currently use CSplitterWnd, replace with CMinSplitterWnd (Note: remember to include MinSplitterWnd.h):
  3. #include "MinSplitterWnd.h" // Minimum size splitter.
    ....
    class CMyWnd : public CMDIChildWnd
    {
        ....
        CMinSplitterWnd m_wndSplitter;
        ....
    };
    
  4. Call SetRowInfo and SetColumnInfo as necessary, specifying the required minimum row and column sizes: (this is normally done in the parent window's OnCreateClient function)
  5. ....
    m_wndSplitter.CreateStatic( this, 2, 2 );      // Create with 2 rows and 2 columns.
    m_wndSplitter.SetRowInfo( 0, 100, 100 );       // Set ideal and minimum size to 100.
    m_wndSplitter.SetRowInfo( 1, 100, 100 );       // Set ideal and minimum size to 100.
    m_wndSplitter.SetColumnInfo( 0, 100, 100 );    // Set ideal and minimum size to 100.
    m_wndSplitter.SetColumnInfo( 1, 100, 100 );    // Set ideal and minimum size to 100.
    ....
    
  6. In the splitter's parent window, add a message handler for OnWindowPosChanging (this prevents the user from sizing the window too small) and add the following code to it:
  7. void CMyWnd::OnWindowPosChanging(WINDOWPOS FAR* lpwndpos) 
    {
    	//	Don't do anything if minimized.
    	if ( IsIconic() )
    	{
    		CMDIChildWnd::OnWindowPosChanging( lpwndpos );
    		return;
    	} // if
    
    	//	Calculate the window rect if we have no client area.
    	CRect rc( 0, 0, 0, 0 );
    	CalcWindowRect( rc );
    
    	//	Add on the minimum client width and height from the splitter.
    	int nMinWidth	= rc.Width() + m_wndSplitter.GetMinClientWidth();
    	int nMinHeight	= rc.Height() + m_wndSplitter.GetMinClientHeight();
    
    	//	Get the current window size.
    	CRect rcWindow;
    	GetWindowRect( rcWindow );
    	GetParent()->ScreenToClient( rcWindow );
    
    	//	If trying to size too small...
    	if ( lpwndpos->cx < nMinWidth )
    	{
    		//	If dragging left border right...
    		if ( rcWindow.left < lpwndpos->x )
    		{
    			//	How much over are we?
    			int nOver = nMinWidth - lpwndpos->cx;
    			
    			//	Adjust left coord.
    			lpwndpos->x -= nOver;
    
    		} // if
    
    		//	Fix width.
    		lpwndpos->cx = nMinWidth;
    	} // if
    
    	//	If trying to size too small...
    	if ( lpwndpos->cy < nMinHeight )
    	{
    		//	If dragging top border down...
    		if ( rcWindow.top < lpwndpos->y )
    		{
    			//	How much over are we?
    			int nOver = nMinHeight - lpwndpos->cy;
    			
    			//	Adjust left coord.
    			lpwndpos->y -= nOver;
    		} // if
    		
    		//	Fix height.
    		lpwndpos->cy = nMinHeight;
    	} // if
    }
    
  8. That's it!

Limitation:

If the minimum sizes exceed the initial frame window size, the window will snap when the window is first resized.

Download demo project and executable - 36 KB