Click here to Skip to main content
Click here to Skip to main content

Reusable base class for SplitterWnd

By , 2 Sep 2001
 

Introduction

Have you ever spent time trying to get the splitting windows right, then added a method of switching views and even worse, tried to make the individual splitters to expand over the whole window? And then you want to make the whole damn (sorry) thing persistent for the next time you start the program? Well I did, and every time I had to look up in old code and every time I made errors and every time it took me a long time to get it to work the way I had it planned.

Well, I now sat down and solved it - once for all. By writing a reusable base class. Of course, I had a little help from many useful articles posted by this and other sites. The methods ShowColumn and HideColumn are taken from an article posted by Oleg Galkin on www.codeguru.com, the articles by Caroline Englebienne, Adrian Roman and Dongik Shin helped me writing the methods to support switchable views.

And now I'm ready to share once more. You may use this class for your own projects as you like, but it is AS IS, use at your own risk, I cannot be held responsible for any damage...blah blah blah ...

To use this base class is simple, however there are a few things you need to consider, else you will get one of the many asserts from within the CSplitterWnd.

This class uses only static splitters and will only split each window once, either vertically or horizontally. Once the window is split, you can split one ore both panes again and again and... Have a look at the screen shot above. I simple split the first window into two panes, a left and right one. Then I split the left pane again, this time into a top and bottom pane. The bottom pane is now split again vertically and so on.

To do this, you need to include the source files ST_splitterwnd.h and ST_splitterwnd.cpp into your project.

Then add a ST_SplitterWnd member for each split to your CMainFrame:

    ST_SplitterWnd* m_pSplitterWnd;
    ST_SplitterWnd* m_pSplitterWnd2;
    ST_SplitterWnd* m_pSplitterWnd3;
    ST_SplitterWnd* m_pSplitterWnd4;

In CMainFrame::OnCreateClient, you need to create the first ST_SplitterWnd:

    m_pSplitterWnd = new ST_SplitterWnd();
    m_pSplitterWnd->Create(this,NULL,NULL,pContext,true);

The Create method is defined as follows:

    bool Create(CWnd* pParentWnd, // this will do
      CRuntimeClass* pView1, // Add the view for 
                             // the left(or top) pane or NULL
      CRuntimeClass* pView2, // Add the view for
                             // the right(or bottom) pane or NULL
      CCreateContext* pContext, // pass the pContext pointer
                                // from the OnCreateClient
      bool bVertical, // set to true if the window
                      // is split vertically else false
      int nID = AFX_IDW_PANE_FIRST); // this parameter
                                     // does not need redefinition
{

Note: If you want to split a window into further subdivisions, pass NULL to the pView1 and/or pView2 parameter. If you fail to do this, the application will assert.

The view1 and view2 is used to pass the view class to the SplitterWnd, just like it is done with the 'normal' CSplitterWnd. It has to be passed using the macro RUNTIME_CLASS, e.g.:

RUNTIME_CLASS(CSplitterWndTestView3)

Use the method AddSubDivision to apply a further split:

   m_pSplitterWnd2 = 
     m_pSplitterWnd->AddSubDivision(LEFT_SIDE,
     RUNTIME_CLASS(CSplitterWndTestView3),NULL,pContext,false);

The above sample will split the left pane horizontally and fill the top pane with a view, while leaving the bottom part empty for further splitting by passing NULL. The method AddSubDivision is defined as follows:

    ST_SplitterWnd* AddSubDivision(int nSide, // use LEFT_SIDE, 
                                              // RIGHT_SIDE, TOP_SIDE
                                              // or BOTTOM_SIDE
        CRuntimeClass* pView1, // Add the view for the
                               // left(or top) pane or NULL
        CRuntimeClass* pView2, // Add the view for the
                               // right(or bottom) pane or NULL
        CCreateContext* pContext, // pass the pContext pointer
                                  // from the OnCreateClient
        bool bVertical); // true for a vertical split,
                         // false for a horizontal split

Basically, the parameters are used in the same way as the Create parameters. The first parameter (nSide) is used to describe the pane in which the split has to be added. Four constants (LEFT_SIDE, RIGHT_SIDE, TOP_SIDE and BOTTON_SIDE) are defined for this purpose. The last parameter tells the method to perform a vertical split (true) or a horizontal split (false). The AddSubDivision returns a pointer to a new instance of a ST_SplitterWnd object which can be split again (and again..):

   m_pSplitterWnd3 = m_pSplitterWnd2->AddSubDivision(BOTTOM_SIDE,
                             NULL,
                             RUNTIME_CLASS(CSplitterWndTestView2),
                             pContext,
                             true);   
   m_pSplitterWnd4 = m_pSplitterWnd3->AddSubDivision(LEFT_SIDE,
                             RUNTIME_CLASS(CSplitterWndTestView4),
                             RUNTIME_CLASS(CSplitterWndTestView5),
                             pContext,
                                        false);

An additional feature of this class is the possibility to switch between views within a pane. In order to do this, you use the method AddView. Note: When using AddView, the pane to which the views must be added must not contain a view, with other words, they must be initialized with NULL just like the pane which will be split once more.

    m_nViewNo1 = m_pSplitterWnd->AddView(RIGHT_SIDE,
                         RUNTIME_CLASS(CSplitterWndTestView),
                         pContext);
    m_nViewNo2 = m_pSplitterWnd->AddView(RIGHT_SIDE,
                         RUNTIME_CLASS(CSplitterWndTestView6),
                         pContext);

The method AddView is defined as follows:

        int AddView(int nSide, // use LEFT_SIDE, RIGHT_SIDE,
                              // TOP_SIDE or BOTTOM_SIDE
          CRuntimeClass * pViewClass,  // Add the view for the 
          CCreateContext* pContext);  // pass the pContext pointer
                                     // from the OnCreateClient

Basically that will do the job. There are three more methods of interest: SetInitialStatus, SwitchToView and ToggleSide:

  • SetInitialStatus is used to restore the settings, such as size and position of each pane, from the registry.
  • SwitchToView toggles between multiple views within a pane.
  • ToggleSide hides and displays a pane.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Daniel Zuppinger
Chief Technology Officer
Switzerland Switzerland
Member
Professional IT developer since 1983. First projects with Cobol, then Pascal, Modula2, C and since Visual C++ 1.0 also with C++. Works since 1986 as Consultant, between 1990 and 2008 for Infobrain in Switzerland, currently employed by enValue (also Switzerland).
Current field is the project management and development of software for Bank applications.
Married, two daughters, Hobbies : Paragliding, Orienteering, Mountainbiking, Photography

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.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionMFC applicationmembertaimmoor25 Feb '12 - 5:10 
i am new if you place that specific code here for my requirement...i am specialy thankful to you.for SDI application one row and second row splitted into two column...plz my request.
Questionsplitting windowmembertaimmoor25 Feb '12 - 2:00 
i want static splitting of SDI application into two row and 2nd row again splitted into 2 column like that
 
*******
* *
*******
* | *
* | *
*******
plz provide code as soon as possible..me waits
AnswerRe: splitting windowmemberDaniel Zuppinger25 Feb '12 - 4:50 
Read the article and play around, I'm sure you figure it out. Wink | ;)
Questionsplitterwnd in CMDIFrameWndmemberwuman21 Oct '08 - 18:53 
I need add a splitter to the MDI based application. The left pane still can display multiple doc/view and the right pane will diplsay some controls. Is this possible ?
I searched the web,all the ariticles are talking about adding splitter to the MDI child window.
Thanks for any help!
Generalexcellent !memberRudyRen18 Oct '08 - 18:17 
Great Job.its useful for me.thanks/
QuestionHow to show 3 different views in 3 subpanels in right panel by using splitterwnd?membersrikadi29 Sep '08 - 17:38 
if (!m_nwSplitter.CreateStatic (this, 1, 2)||
!m_nwSplitter.CreateView (0, 0, RUNTIME_CLASS (CNetworkTree),CSize (220,0), pContext))
{
return FALSE;
}

 
if (!m_nwSplitter2.CreateStatic(&m_nwSplitter, 3, 1,WS_CHILD | WS_VISIBLE| WS_BORDER,m_nwSplitter.IdFromRowCol(0, 1))||
!m_nwSplitter2.CreateView(0,0,RUNTIME_CLASS(CNetworkVwList),CSize(0,200), pContext)||
!m_nwSplitter2.CreateView(1,0,RUNTIME_CLASS(CSWPlanView),CSize(0,200), pContext)||
!m_nwSplitter2.CreateView(2,0,RUNTIME_CLASS(CTaskListView),CSize(0,0), pContext))
{
return FALSE;
}
 

before the code was like
CView * pane2 = (CView *)pNwViews->GetPane(0,1);
 
now i want to show one view in right panel ie in m_nwSplitter2.CreateView(0,0,...)..
 
i wrote like CView * pane2 = (CView *)pNwViews->GetPane(0,0);
 
but its not working...
plz help me...
thanx in advance..
GeneralCSpitterWnd with Tabsmembergodspeed1238 Jul '08 - 12:42 
Does anyone know how to put splitterwnd into tabs?
QuestionHow can I use this class in .net 2003?memberxiaod_l17 May '07 - 2:45 
Hi,all
I am a beginner,I want to use this class in .net 2003.When I use it in .net 2002,the project can be compiled but couldn't run. Could you give me any advice?
 
Thanks
GeneralGreat Jobmemberkishine1o1 Feb '07 - 16:42 
New to VC++:->. Your article helps me a lot.Big Grin | :-D
QuestionList View Gone Mad?????memberregisterTHIS9 Oct '06 - 13:49 
Very nice implementation. EXACTLY what I needed and was in the process of doing myself until I found your article. Excellent! And, Thank You. 2 things though -
 
1) was a challenge to figure out how to get and save pointers to my view classes since you cannot use GetPane() reliably. I figured this one out, though.
 
2) My listview window is drawing text 2 3/4 rows below what it should be. The display is awful and if I cannot figure this problem out, will have to pull the code. I am using a virtual list to display an access database, but all I am doing is providing the data the list is asking for. The standard components are doing all the drawing. Something is off - WAY OFF, but I don't know why. Nothing else changed about the app except for the addition of the spillter classes. Does anyone have any suggestions???
 
Thanks!
 

AnswerRe: List View Gone Mad?????membermurray w10 Feb '07 - 16:33 
Thank you!
 
Everything is working as it should, except I also need to ... get and save pointers to my view classes since you (I) cannot use GetPane() reliably. (I tried.)
 
Unlike registerTHIS, I haven't figured this one out, though.
 
Advice?
 
Thanks!
 

GeneralRegarding CSplitter/Multiple Views in SDImemberBhushan198013 Jul '06 - 23:18 
Hi,
I want to create a static splitter in SDI application of mine. I have created an SDI application through the application wizard and have wizard type property pages operating on the execution of New File Command, which is handled in CMainFrame class instead of View class. This is inorder to make it easy to access other view classes that I developed afterwards. My question is, How to create the new view classes in the desired panes? And then get the data from the doc class interact with the view class? I want to achieve this even when view class is not active i.e., not displayed. I want to have 3 vertical panes in my application, with the views in the middle frame changing. I know how to create the static splitter and to create views making the use of RUNTIME_CLASS macros. But I don't know the code that needs to be added in the handler functions to switch the views. Also I don't know how to create multiple frames for the view classes. I want to create atleast one extra frame for atleast one view class that is not a splitter window class. So please help me out with this.
Thank you all for going through my email.
 


 
Bhushan.
Questionhow to register database in windowsxp platformmemberli zhiyuan22 Jun '06 - 20:59 
Dear all friends
 

i installed vc++6.0 and windowsxp system.but vc++6.0 used windowx 95 or 98 platform to develop, so when i build database, encountered problem,"i can't found click 32-bit ODBC icon" in control pane.please inform me how to resolve this problem. thank you.
 
Li Zhiyuan
 
22/06/2006
GeneralWarning Level 4 and Crashesmemberdhawan_boss7 Apr '06 - 18:09 
Hello ,
 
Although the class is quite good and useful , but , according to me , it have some issues.
 
First of all,
On the warning level 4 , it gives around 25 warnings.
 
Second thing is,
i used this class in my project , then
the debug version works fine , but the release version just crashes,without giving any clue why.I want to mention here that , i am using win 32 Unicode Project. Does not give any clue why ?
 
One thing i observed is that in the registry , i dont have any Panes_%d value. I guess it crashed there.
the registry setting is in AddSubdivision() method . What if i am not using that.
 

 
Help me in both of the point.
 

Best Regards,
Nitin Dhawan,

GeneralUpdate Viewmemberhever30 Jan '06 - 6:05 
Hello,
how could I update a view out of another view?
 
I have updated Data in the left View and now I'm going to update the right view to show the data...
GeneralRe: Update Viewmemberhever31 Jan '06 - 7:40 
Here a little bit more about my Problem:
 
I splitted the MainFormView vertical and added to each Pane a View in the OnCreateClient Method of the MainFrame:

m_pRightBottomSplitterWnd = m_pRightSplitterWnd->AddSubDivision(BOTTOM_SIDE, RUNTIME_CLASS(CViewChooser), RUNTIME_CLASS(CView1), pContext, true);

 
Now I click on a Button in the right Pane and going to change the View in the Left Pane. For Example from CFormView to CHTML View or whatever. Therefore I call a Method in the MainFormView Class by clicking the Button, with the following code:
 
m_pRightBottomSplitterWnd->AddView(RIGHT_SIDE, RUNTIME_CLASS(CView2), NULL);
 

But that still doesn't work and I got a runt-time-error. The Debugger stops at the following code, from the SplitterWnd Class:
 
inline void SideToRowCol(int nSide, int* nRow, int* nCol)
{
if (m_bVertical) { //<<< Here it stops and can't access m_bVertical
*nRow = 0;
*nCol = nSide;
}
else {
*nRow = nSide;
*nCol = 0;
}
};

 
I hope you understand my Problem and can help me.
AnswerRe: Update Viewmemberhever31 Jan '06 - 10:45 
Ok,
here's the solution...
 
http://www.codeproject.com/script/comments/forums.asp?forumid=1647&select=1353506&df=100#xx1353506xx
AnswerRe: Update ViewmemberJol7 Sep '06 - 21:47 
can't access - what do you mean ?
If it's GPFing due to a garbage value, maybe you haven't instantiated the class that m_bVertical is a member of?

GeneralRe: Update Viewmembercnsyr13 Apr '06 - 0:00 
first:
add the function in ST_SplitterWnd
CWnd* ST_SplitterWnd::GetWnd(int nSide)
{
int nViewIX = m_nCurrentView[nSide] + 1;
if (nViewIX >= m_views[nSide].size())
nViewIX = 0;
 
return m_views[nSide][nViewIX];
}
next:
In mainfrm.cpp file...
add the code in OnCreateClient function
m_pSplitterWnd = new ST_SplitterWnd();
 
m_pSplitterWnd->Create(this,NULL,NULL,pContext,true);
 
m_nViewNo[0] = m_pSplitterWnd->AddView(LEFT_SIDE,RUNTIME_CLASS(CLeftView),pContext);
m_nViewNo[1] = m_pSplitterWnd->AddView(RIGHT_SIDE,RUNTIME_CLASS(CRightView),pContext);
m_pSplitterWndRight = m_pSplitterWnd->GetWnd(RIGHT_SIDE);
m_pSplitterWnd->SetInitialStatus();
and add the OnNotify method like below
BOOL CMainFrame::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
// TODO: Add your specialized code here and/or call the base class
 
//
NMHDR *pHdr = (NMHDR*)lParam;
if(wParam == IDC_OPTIONSTREE_CTRL && pHdr->code == OT_NOTIFY_SELCHANGE)
{
return m_pSplitterWndRight->SendMessage(WM_NOTIFY, wParam, lParam);
}

return CFrameWnd::OnNotify(wParam, lParam, pResult);
}
next:
in CRightView's add the OnNotify method like below
BOOL CRightView::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
// TODO: Add your specialized code here and/or call the base class
NMHDR *pHdr = (NMHDR*)lParam;
if(wParam == IDC_OPTIONSTREE_CTRL && pHdr->code == OT_NOTIFY_SELCHANGE)
{
CString str;
str = ((NMOPTIONTREE*)pHdr)->otiItem->GetLabelText();
}
 
return CView::OnNotify(wParam, lParam, pResult);
}
last:
add the code at m_otTree created.
// Want to be notified
m_otTree->SetNotify(TRUE, this->GetParent());

GeneralDefault active panememberornatale10 Jan '06 - 5:01 
How can I set the default active pane within the MDI frame in which all the split have been done?
 
I've tried to catch the WM_MDIACTIVE and then something like
 
CView myView * mySplit->GetPane(nXdefault, nYdefault);
myView->SetActiveWindow();

 
The handler get called, but myView doesn't become the active view among all the splits.
 
What's wrong?
 
Thanks so much,
Riccardo.
 

QuestionRegistry Entriesmemberozantopoglu2 Jan '06 - 23:40 
Hi All
there is a problem with registry entries used for the storage and retrieval of the pane sizes. Since the data structure holding the splitters is a binary tree and the Registry entries keys "sSubKey" are named using the member variable "m_nLevel" the panes which have the same level are treated to be of same size which is not neccesarrily so. Has anyone got a solution for this problem?
Thanks for neat code you have submitted by the way
 
ozantopoglu
Questionhow could u split a 3X3 view, it is a 3 column and 3 row view.memberskygg14 Nov '05 - 20:35 

i can not find the way to do this with this class,thank u in advance!
Questionproblems with ST_SplitterWnd and CFrameWndmember#93709 Nov '05 - 10:13 
Hi,
 
I want to use a CFrameWnd with a DialogBar and some views for the right pane. Attached to the Dialog Bar is a CTabCtrl for switching between the views in the CFrameWnd. The problem now is, that a small part of one of the views is visible within the first view at the left upper corner.
When I use a standard CSplitterWnd I don't have this effect.
 
What's wrong?
 
Thank's
#9370
GeneralDoesn't WorkmemberDave22n2 Nov '05 - 7:23 
This code is broken. Any modifications to the example case causes problems. It certainly doesn't work with VC++ 6.
AnswerI thought so too...memberBoeroBoy27 Feb '06 - 11:43 
Then I commented out all the resize events. Even clicking the toolbar buttons tends to crash the example. Maybe the example would have been simpler without the events. Cool deal.

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

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130523.1 | Last Updated 3 Sep 2001
Article Copyright 2001 by Daniel Zuppinger
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid