Topic : Splitter Window
Author : Unknown
Page : 1 Next >>
Go to page :


Splitter Window


A splitter window resides within the frame window. It is divided into several panes, each pane can have a different size. Splitter window provides the user with several different views for monitoring data contained in the document at the same time. Normally, the size of each pane can be adjusted freely, this gives the user a better view of data. There are two types of splitter windows: Dynamic Splitter Window and Static Splitter Window. For a dynamic splitter window, all views within the splitter window are of the same type. The user can create new panes or remove old panes on the fly. For a static splitter window, the views could be of different types and the number of panes has to be fixed at the beginning. In this case, the user can not add or delete views after the program has started.

Both SDI and MDI applications can have splitter windows. In an SDI application, the splitter window is embedded in the mainframe window. In an MDI application, it is embedded in the child frame window.

1 Implementing Static Splitter Windows

In MFC, class CSplitterWnd is used to implement window splitting. To split a window into several panes, we must first declare a CSplitterWnd type variable in the frame window class. One CSplitterWnd can divide window into M(N sub-panes. The splitter window can be nested, which means we can further split a single pane into several sub panes by using another CSplitterWnd type variable. So if we want to create an unevenly divided splitter window, we need to declare more than one CSplitterWnd type variables.

For example, if we want to create a splitter window that has two rows, the first row has two columns and the second row has two columns, we need to first split the client area into a 1(2 splitter window, then split the first row into a 2(1 splitter window (Figure 3-1).

(Figure omitted)

To create static splitter window, first we need to declare CSplitterWnd type variable(s) in the frame window class, then in frame window's OnCreateClient(...) member function, call functions CSplitterWnd::CreateStatic(...) and CSplitterWnd::CreateView(...). Here, function CSplitterWnd:: CreateStatic(...) is used to split the window into several panes and CSplitterWnd::CreateView(...) is used to attach a view to each pane.

Sample application 1\Sdi\Spw demonstrates how to implement splitter window. It is generated by Application Wizard, with all settings set to default ones. Four main classes used to implement the application are CSpwApp, CMainFrame, CSpwDoc and CSpwView.

Each pane of the splitter window must be attached with a view in order to make it work. The view could be implemented by deriving class from any of the standard view classes: CView, CScrollView, CRichEditView, CListView, CTreeView etc. In the sample, besides the default view CSpwView created by the Application Wizard, two other classes are derived from CFormView and CEditView, which will be used to implement different panes of the splitter window.

Class CFormView is a standard MFC class that can be used to create view window from dialog template. A CFormView class must have a corresponding dialog template resource, which will be used to create the view. To implement a form view, we must first design dialog template, then derive a new class from CFormView.

In the sample, the dialog template used to implement the form view is IDD_DIALOG_VIEW. Its styles are set to "Child" and "No border", this is exactly the same with that of dialog bar (This is because both splitter window and dialog bar must be child windows). The dialog template contains a static text control and a multiple-line edit box. By double clicking on the dialog template resource, we will be prompted to add a new class for it. In this case the template resource ID will be automatically selected to be used by the new class. In the sample application, the new class is named CSpwFView. If the dialog template is not open when adding this new class, we must select the dialog ID by ourselves (Figure 3-2).

(Figure omitted)

The other pane of the splitter window is implemented using edit view. The new class for this window is derived from CEditView, and its name is CSpwEView.

To split a window, we need to call function CSplitterWnd::CreateStatic(...), which has five parameters:

(Cde omitted)

The first parameter pParentWnd is a CWnd type pointer that points to the parent window. Because a splitter window is always the child of frame window, this parameter can not be set to NULL. The second and third parameters specify the number of rows and columns the splitter window will have. The fourth parameter dwStyle specifies the styles of splitter window, whose default value is WS_CHILD | WS_VISIBLE. The fifth parameter, nID, identifies which splitter window is being created. This is necessary because within one frame window, we can create several nested splitter windows. For the root splitter window (The splitter window whose parent window is the frame window), this ID must be AFX_IDW_PANE_FIRST. For other nested splitter windows, this ID need to be obtained from the parent splitter windows by calling function CSplitterWnd::IdFromRowCol(...), and passing appropriate column and row coordinates to it. The following is the format of this function:

int CSplitterWnd::IdFromRowCol(int row, int col);

To attach a specific view to a pane, we need to call function CSplitterWnd::CreateView(...), which also has five parameters:

(Code omitted)

The first two parameters specify which pane is being created. The third parameter specifies what kind of view will be used to create this pane. Usually macro RUNTIME_CLASS must be used to obtain a CRuntimeClass type pointer. The fifth parameter is a creation context used to create the view. Within CMainFrame::OnCreateClient(...), the creation context is passed through the second parameter of this function.

In the sample application, we first use m_wndSpMain to call function CSplitterWnd:: CreateStatic(...) to split the client window into a 2(1 splitter window. Then, we use this variable to call CSplitterWnd::CreateView(...) and pass two 0s to the first two parameters of this function (This specifies (0, 0) coordinates). This will attach a new view to the left pane of the splitter window. Next we use m_wndSpSub to call CSplitterWnd::CreateStatic(...) to further split the right pane into a 1(2 splitter window, and call CSplitterWnd::CreateView(...) twice to create views for the two panes. At last, instead of calling function CMainFrame::OnCreateClient(...), a TRUE value is returned. This can prevent the default client window from being created.

The following steps show how the static splitter window is implemented in the sample:

1) Declare two CSplitterWnd type variables in class CMainFrame:

class CMainFrame : public CFrameWnd

{

......

protected:

CStatusBar m_wndStatusBar;

CToolBar m_wndToolBar;

CSplitterWnd m_wndSpMain;

CSplitterWnd m_wndSpSub;

......

}


Variable m_wndSpMain will be used to split the mainframe client window into a 2(1 splitter window, and m_wndSpSub will be used to further split the right column into a 1(2 splitter window.

2) In function CMainFrame::OnCreateClient(...), create splitter windows and attach views to each pane:

(Code omitted)

For an MDI application, everything is almost the same except that here CChildFrame replaces class CMainFrame. We can create an MDI application, declare m_wndSpMain and m_wndSpSub variables in class CChildFrame, and add code to CChildFrame::OnCreateClient(...) to create splitter windows. The code required here is exactly the same with implementing splitter window in an SDI application. Sample 1\MDI\Spw demonstrates this.

2 Dynamic Splitter Window

Once we understand how to create static splitter window, it is easier for us to create dynamic splitter window because it takes fewer steps. For a dynamic splitter window, all panes are created to be the same type of view, so there is no need to call function CSplitterWnd::CreateView(...) for each individual pane. Also, instead of calling CSplitterWnd::CreateStatic(...), we need to call function CSplitterWnd:: Create(...) to create dynamic splitter window within function CFrameWnd::OnCreateClient(...). The following is the format of function CSplitterWnd::Create(...):

BOOL CSplitterWnd::Create

(

CWnd* pParentWnd,

int nMaxRows, int nMaxCols,

SIZE sizeMin,

CCreateContext* pContext,

DWORD dwStyle=WS_CHILD | WS_VISIBLE |WS_HSCROLL | WS_VSCROLL | SPLS_DYNAMIC_SPLIT,

UINT nID=AFX_IDW_PANE_FIRST

);


The difference between function CSplitterWnd::CreateStatic(...) and CSplitterWnd::Create(...) is that when creating dynamic splitter window, we need to specify the maximum number of rows and columns. The maximum values of nMaxRows and nMaxCols parameters are both 2, which means that a window can be split to have at most 2x2 panes.

The Application Wizard has a built-in feature to add dynamic splitter window to the applications. In step 4 of the Application Wizard, if we press "Advanced..." button, an "Advanced Options" property sheet will pop up. By clicking "Window styles" tab then checking "Use split window" check box, code will be automatically added to the application for implementing dynamic split window (static splitter window can not be created this way).

It is also simple to implement splitter window manually. Like creating static split window, first we need to declare a CSplitterWnd type variable in class CMainFrame (In MDI applications, we need to do this in class CChildFrame). Then we can use Class Wizard to override function OnCreateClient(...). Within the overridden function, we can call CSplitterWnd::Create(...) to create splitter window.

Sample 2\Spw demonstrates how to create dynamic splitter window in an SDI application. The application is created from Application Wizard with all default settings. Then a new variable m_wndSp is declared in class CMainFrame, which will be used to implement the splitter window. In function CMainFrame::OnCreateClinet(...),

Page : 1 Next >>