Click here to Skip to main content
Licence 
First Posted 13 Jan 2000
Views 207,847
Bookmarked 86 times

CSplitterWndEx : indicating splitter window focus, and automatic splitting

By | 13 Jan 2000 | Article
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 in 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
    CSplitterWnd m_wndSplitter;

    with

    CSplitterWndEx m_wndSplitter;

Now, you have a new class to work with.

4. Setting the focus

Add the following 2 public methods to CSplitterWndEx:

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).

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:
    ((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:
    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:

Public:
    bool m_bSplittingDone;
protected :
    bool m_bIsAutomaticSplit;

In the constructor, initialize these members:

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:

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 immediatelly 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 automaitic to true 
    m_bIsAutomaticSplit = true;

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

    //restore immediatelly the old mouse poition
    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:

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:

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:

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

About the Author

Stephane Routelous

Software Developer (Senior)

Canada Canada

Member



Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
QuestionThe code does not work for more than 2 splits PinmemberShashidhar Kamath12:36 14 Dec '11  
GeneralSplitterbars without using MFC Pinmemberdouwe.faber8:00 20 May '06  
GeneralAdding an OpenGL 3D View Pinmemberdavegobin9:00 4 Mar '06  
Generalall 4 views are the same PinmemberDevil for ever10:39 25 Nov '05  
Generala mistake PinmemberDevil for ever10:37 25 Nov '05  
GeneralVS .net bug resolved Pinmemberl00p1n622:32 11 Jul '05  
QuestionDownload not working? PinsussAnonymous10:39 14 May '05  
AnswerRe: Download not working? PinmemberStephane Routelous10:46 14 May '05  
GeneralRe: Download not working? PinsussAnonymous10:55 14 May '05  
GeneralRe: Download not working? PinsussAnonymous11:01 14 May '05  
GeneralRe: Download not working? PinmemberStephane Routelous11:25 14 May '05  
GeneralRe: Download not working? PinsussAnonymous12:33 14 May '05  
General3d view Pinmemberradha vijay8:12 29 Jan '05  
GeneralRe: 3d view Pinmemberdavegobin8:56 4 Mar '06  
General3 static splitter window Pinsussweilun20:02 31 Aug '04  
GeneralIt doesn't work Pinmemberhaoshenghan22:34 16 Apr '04  
GeneralSplitter PinmemberXBenno15:21 1 May '03  
Generalsplitter window PinsussAnonymous10:19 24 Apr '03  
GeneralExcellent Substitute for glScissor PinmemberSharjith23:48 24 Feb '03  
Generalsplitter with propertysheet Pinsusssuguna22:35 5 Aug '02  
GeneralRe: splitter with propertysheet Pinmemberwind_needed22:36 1 Sep '02  
Generalomsplitter with propertysheet Pinsusssuguna22:32 5 Aug '02  
QuestionWhat about SDI PinsussAnonymous1:43 18 Jul '02  
GeneralVery Much There PinmemberMohit Jain23:19 15 Apr '02  
GeneralRe: Very Much There PinmemberSteve Shanafelt13:30 17 Apr '02  

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

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

Permalink | Advertise | Privacy | Mobile
Web04 | 2.5.120517.1 | Last Updated 14 Jan 2000
Article Copyright 2000 by Stephane Routelous
Everything else Copyright © CodeProject, 1999-2012
Terms of Use
Layout: fixed | fluid