Click here to Skip to main content
15,879,535 members
Articles / Desktop Programming / MFC

CSplitterWndEx: Indicating Splitter Window Focus, and Automatic Splitting

Rate me:
Please Sign up or sign in to vote.
4.96/5 (19 votes)
13 Jan 2000 282.8K   6.7K   101   42
A tutorial that shows how to automatically split a view, and also how to indicate which view has the focus

Sample Image - AutomaticSplitter.jpg

Introduction

I'm developing a CAD/CAM application with MFC using the Document/View framework. In this application, the C<MyProject>View contains a 3D view with 3D objects. In the CAD/CAM industry, we need different points of views for the 3D Window, so I implemented an Automatic Split function, which tiles the 3D views in 4 panes: Front, Top, Left and Axonometric View.

Unfortunately, I cannot give a sample of the CAD/CAM Application (because it is using third party libraries), but you will find a simple MFC project showing the Automatic split capability, and the focus.

This tutorial explains how to set the focus on the current pane of a Splitted View and how to automatically split a View (without giving the position of the splitterbar).

Note: For the focus, I’m using code that I found somewhere on the Internet or in a book, but I cannot remember where. If you have written this code, contact me and I will give you credits for your work.

1. Creating the Project

You can use the MFC Application wizard to generate the code of your project:

  • Open Visual C++.
  • Select File | New | MFCAppWizard (EXE).
  • Give a Name (MyProj) and a path.
  • Keep the default options (using direct Finish).

Your project is done; you can compile it and run it.

If you run it, you can see in the Window menu, there is no split option.

2. Adding the Splitter Bars

To do this, you should use the Component Gallery:

  • Select Project | Add To Project | Components and Controls.
  • Go in Visual C++ Component and select SplitterBar.
  • Select Both / OK and Close.

Now, if you see the CChildFrame class, you have the OnCreateClient methods, which creates the SplitterWnd. Open your Resource View and in the Menu IDR_MYPROJTYPE, add under Window the entry &Split with the ID ID_WINDOW_SPLIT.

Build the executable, and test the "Split" function (it should work).

3. Creating a New Class which Inherits from CSplitterWnd

  • Select Insert | New Class
  • Class Type : MFC
  • Name: CSplitterWndEx
  • BaseClass: Generic CWnd
  • Edit the files SplitterWnd.h and SplitterWnd.cpp, and replace all the CWnd objects by CSplitterWnd objects
  • Edit ChildFrm.h, and insert #include "SplitterWndEx.h" in the top of the include file, and replace:
    C++
    CSplitterWnd m_wndSplitter;

    with:

    C++
    CSplitterWndEx m_wndSplitter;

Now, you have a new class to work with.

4. Setting the Focus

Add the following 2 public methods to CSplitterWndEx:

C++
void OnDrawSplitter(CDC* pDC, ESplitType nType, const CRect& rectArg);
void RefreshSplitBars(void);

void CSplitterWndEx::OnDrawSplitter(CDC* pDC, 
    ESplitType nType, const CRect& rectArg)
{
    int x_ActivePane, y_ActivePane; 
    COLORREF hilightcolor = RGB(255,255,0);
    
    GetActivePane(x_ActivePane, y_ActivePane);
    if( ((GetRowCount()>1) ||(GetColumnCount()>1)) 
                        && (nType == splitBorder))
    {
        int pRow = 0;
        int pCol = 0;
        if(rectArg.top)
        {
            pRow = 1;
        }
        if(rectArg.left)
        {
            pCol = 1;
        }
        if((pCol == y_ActivePane) && (pRow == x_ActivePane)) 
        {
            if (pDC == NULL)
            {
                RedrawWindow(rectArg, NULL, RDW_INVALIDATE|RDW_NOCHILDREN);
                return;
            }
            ASSERT_VALID(pDC);
            CRect rect = rectArg;pDC->Draw3dRect(rect, 
                               hilightcolor, hilightcolor);
            int dx = -GetSystemMetrics(SM_CXBORDER);
            int dy = -GetSystemMetrics(SM_CYBORDER);
            rect.InflateRect(dx,dy);
            pDC->Draw3dRect(rect, hilightcolor, hilightcolor);
            return;
        }
    }
    CSplitterWnd::OnDrawSplitter(pDC,nType,rectArg);
}

This method draws an extra Rectangle around the ActivePane with the color hilightcolor.

Note: You can set 2 colors (see help for Draw3dRect).

C++
void CSplitterWndEx::RefreshSplitBars(void)
{
    CRect rectInside;
    GetInsideRect(rectInside);
    DrawAllSplitBars(NULL, rectInside.right, rectInside.bottom);
}

This method calls the refresh for the splitbars.

You have all your methods to draw the focus window. You just need to call them:

  • Using the Class Wizard, add handlers for the messages WM_KILLFOCUS and WM_SETFOCUS to CMyProjView.
  • In both methods, write the following line:
    C++
    ((CChildFrame*)GetParentFrame())->m_wndSplitter.RefreshSplitBars();
  • In the CMyProjView.cpp, add the include: #include "ChildFrm.h"
  • Go to the CChildFrame include file, and change the access to:
    C++
    CSplitterWndEx m_wndSplitter;
    from protected to public.
  • Build the project, and run it.

Select Split in the Window menu. When you click a pane, a yellow border is drawn. It shows which pane has the focus.

Automatic Splitting

The Automatic-Splitting is the capability to split a view in 4 views, but without mouse event. It means that the CView is split into 4 views where newWidth = oldWidth / 2 and newHeight = oldHeight / 2.

First, add to the CSplitterWnd class 2 booleans:

C++
Public:
    bool m_bSplittingDone;
protected :
    bool m_bIsAutomaticSplit;

In the constructor, initialize these members:

C++
CSplitterWndEx::CSplitterWndEx()
{
    m_bIsAutomaticSplit = false;
    m_bSplittingDone = false;
}

To call the splitting function, you need to use CSplitterWnd::DoKeyboardSplit();.

We write 4 new methods to the class:

C++
public:
    BOOL DoAutomaticSplit();          // new method
    BOOL DoKeyboardSplit();           // overload the CSplitterWnd::DoKeyboardSplit();
protected:
    void StartTracking(int ht);       // overload the CSplitterWnd::StartTracking
    void StopTracking(BOOL bAccept);  // overload the CSplitterWnd::StopTracking

void CSplitterWndEx::StartTracking(int ht)
{
    //save the current cursor ...
    HCURSOR theCurrentCursor = GetCursor();

    CSplitterWnd::StartTracking(ht); 

    if ( m_bIsAutomaticSplit )
    {
        //...and restore it immediately if in AutomaticSplit mode
        SetCursor(theCurrentCursor);
    }
}

void CSplitterWndEx::StopTracking(BOOL bAccept)
{
    CSplitterWnd::StopTracking(bAccept);

    //now the is splitting done
    m_bIsAutomaticSplit = false;
    m_bSplittingDone = true;
}

BOOL CSplitterWndEx::DoAutomaticSplit()
{
    //save the current mouse position
    POINT theInitialMousePosition;
    GetCursorPos(&theInitialMousePosition);

    //set the splitting done to false ( of course )
    m_bSplittingDone = false;

    //and automatic to true 
    m_bIsAutomaticSplit = true;

    //do the split
    BOOL RetVal = CSplitterWnd::DoKeyboardSplit();

    //restore immediately the old mouse position
    SetCursorPos(theInitialMousePosition.x,theInitialMousePosition.y);
    return RetVal;
}

BOOL CSplitterWndEx::DoKeyboardSplit()
{
    m_bSplittingDone = false;
    m_bIsAutomaticSplit = false;
    return CSplitterWnd::DoKeyboardSplit();
}

We also need to overload the OnMouseMove event:

C++
void CSplitterWndEx::OnMouseMove(UINT nFlags, CPoint pt)
{
    if ( m_bIsAutomaticSplit )
    {
        //if AutomaticSplit mode : We are not able 
        //to choose the position of the splitters
        // -> Exiting to next step
        StopTracking(TRUE);
        return;
    }
    CSplitterWnd::OnMouseMove(nFlags,pt);
}

Note, you will need to call the DoAutomaticSplit method. You can call it in the CChildFrame class:

C++
void CChildFrame::AutomaticSplit()
{
    // set the timer ( just a trick make an action once the splitting is done )
    KillTimer(1);  // Destroy the old timer
    SetTimer(1, 10 , NULL); // Creates a new timer (index = 1 ; time = 10ms)

    m_wndSplitter.DoAutomaticSplit();
}

void CChildFrame::OnTimer(UINT nIDEvent) 
{
    if ( m_wndSplitter.m_bSplittingDone ) // if the splitting is done
    {
        KillTimer(1); // kill the timer
        // ( just a trick make an action once the splitting is done ) 

        //loop on the row & columns
        int nbRow = m_wndSplitter.GetRowCount();
        int nbCol = m_wndSplitter.GetColumnCount(); 
        for ( int r = 0; r < nbRow ; r++ ) 
        { 
            for  ( int c=0  ; c <  nbCol ; c++ )
            {
                CMyProjView* theView = (CMyProjView*)m_wndSplitter.GetPane(r,c);
                if ( r==0 && c== 0)
                    //top-lefttheView->DoSomething(RGB(255,0,0));
                else if ( r==0 && c== 1)
                    //top-righttheView->DoSomething(RGB(0,255,0));
                else if ( r==1 && c== 0)
                    //bottom-lefttheView->DoSomething(RGB(0,0,255));
                else if ( r==1 && c== 1)
                  //bottom-righttheView->DoSomething(RGB(255,255,0));
            }
        }
    }
}

Here, I’m using a trick with a timer to do something when the splitting is done.

Now, you can call the CChildFrame::AutomaticSplit() method to split the CView.

For example, with the Class Wizard, you can create a new entry in the Window menu, and add the call to AutomaticSplit:

C++
void CChildFrame::OnWindowAutomaticsplit() 
{
    AutomaticSplit();
}

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
Technical Lead Oracle
Canada Canada
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionThe code does not work for more than 2 splits Pin
Shashidhar Kamath14-Dec-11 12:36
Shashidhar Kamath14-Dec-11 12:36 
GeneralSplitterbars without using MFC Pin
douwe.faber20-May-06 8:00
douwe.faber20-May-06 8:00 
GeneralAdding an OpenGL 3D View Pin
davegobin4-Mar-06 9:00
davegobin4-Mar-06 9:00 
Generalall 4 views are the same Pin
Devil for ever25-Nov-05 10:39
Devil for ever25-Nov-05 10:39 
Generala mistake Pin
Devil for ever25-Nov-05 10:37
Devil for ever25-Nov-05 10:37 
GeneralRe: a mistake Pin
Southmountain30-Sep-21 5:23
Southmountain30-Sep-21 5:23 
GeneralVS .net bug resolved Pin
l00p1n611-Jul-05 22:32
l00p1n611-Jul-05 22:32 
QuestionDownload not working? Pin
Anonymous14-May-05 10:39
Anonymous14-May-05 10:39 
AnswerRe: Download not working? Pin
Stephane Routelous14-May-05 10:46
Stephane Routelous14-May-05 10:46 
GeneralRe: Download not working? Pin
Anonymous14-May-05 10:55
Anonymous14-May-05 10:55 
GeneralRe: Download not working? Pin
Anonymous14-May-05 11:01
Anonymous14-May-05 11:01 
The full error we all get is:

Internet Explorer cannot download AutomaticSplitter.zip from secure.codeproject.com
The file could not be written to the cache

you are able to download with a different browser?
GeneralRe: Download not working? Pin
Stephane Routelous14-May-05 11:25
Stephane Routelous14-May-05 11:25 
GeneralRe: Download not working? Pin
Anonymous14-May-05 12:33
Anonymous14-May-05 12:33 
General3d view Pin
radha vijay29-Jan-05 8:12
radha vijay29-Jan-05 8:12 
GeneralRe: 3d view Pin
davegobin4-Mar-06 8:56
davegobin4-Mar-06 8:56 
General3 static splitter window Pin
weilun31-Aug-04 20:02
weilun31-Aug-04 20:02 
GeneralIt doesn't work Pin
Ventruing16-Apr-04 22:34
Ventruing16-Apr-04 22:34 
GeneralSplitter Pin
XBenno1-May-03 15:21
XBenno1-May-03 15:21 
Generalsplitter window Pin
Anonymous24-Apr-03 10:19
Anonymous24-Apr-03 10:19 
GeneralExcellent Substitute for glScissor Pin
Sharjith24-Feb-03 23:48
professionalSharjith24-Feb-03 23:48 
Generalsplitter with propertysheet Pin
suguna5-Aug-02 22:35
suguna5-Aug-02 22:35 
GeneralRe: splitter with propertysheet Pin
wind_needed1-Sep-02 22:36
wind_needed1-Sep-02 22:36 
Generalomsplitter with propertysheet Pin
suguna5-Aug-02 22:32
suguna5-Aug-02 22:32 
QuestionWhat about SDI Pin
Anonymous18-Jul-02 1:43
Anonymous18-Jul-02 1:43 
GeneralVery Much There Pin
Mohit Jain15-Apr-02 23:19
Mohit Jain15-Apr-02 23:19 

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.