Export (0) Print
Expand All
MFC
Expand Minimize

TN029: Splitter Windows 

NoteNote

The following technical note has not been updated since it was first included in the online documentation. As a result, some procedures and topics might be out of date or incorrect. For the latest information, it is recommended that you search for the topic of interest in the online documentation index.

This note describes the MFC CSplitterWnd class, which is used to provide window splits and to manage the resizing of other Pane windows.

NoteNote

Be sure to read Technical Note 20 regarding use of IDs and valid ID ranges.

A CSplitterWnd supports two different styles of splitting windows.

In "static splitters," the panes are created when the splitter window is created, and the order and number of panes never change. Splitter bars are used to resize the different panes, and the different panes are usually of different view classes. The Visual C++ graphics editor and the Windows File Manager are examples of programs that use this splitter style. Splitter boxes are not used by this style of splitter.

In "Dynamic splitters," additional panes are created and destroyed as the user splits and un-splits new views. This splitter starts out with a single view, and splitter boxes are provided to initiate splitting. If the view is split in one direction, an additional view object is dynamically created to represent the new pane. If the view is split in two directions (possible with the keyboard interface), then three new views are created to represent the three new panes. When the split is active, the splitter box is drawn as a splitter bar between the panes. Additional view objects are destroyed when the user removes a split, but the original view (row 0, column 0) remains until the splitter window itself is destroyed. Microsoft Excel and Microsoft Word are examples of the dynamic splitter style.

When creating either kind of splitter window, you must specify the maximum number of rows and columns that the splitter will manage. For a static splitter, panes must be created to fill all the rows and columns. For a dynamic splitter, the first pane is automatically created when the CSplitterWnd is created.

The maximum number of panes you can specify for static splitters is 16 rows by 16 columns. The recommended configurations are:

  • 1 row x 2 columns : usually with dissimilar panes

  • 2 rows x 1 column : usually with dissimilar panes

  • 2 rows x 2 columns : usually with similar panes

The maximum number of panes you can specify for dynamic splitters is 2 rows by 2 columns. The recommended configurations are:

  • 1 row x 2 columns : for columnar data

  • 2 rows x 1 column : for textual or other data

  • 2 rows x 2 columns : for grid or table oriented data

Many of the MFC sample programs use splitter windows directly or indirectly. The MFC General sample VIEWEX illustrates several uses of static splitters, including how to place a splitter in a splitter.

ClassWizard will also create a new multiple document interface (MDI) Child frame window class which contains a splitter window. For more information on splitter windows, see Multiple Document Types, Views, and Frame Windows.

Terminology of the parts of a CSplitterWnd and related objects.

CSplitterWnd:

This is a window that provides pane-splitting controls and scroll bars that are shared between all panes on a row or column. Rows and columns are specified with zero-based numbers [that is, the first pane is row = 0 and column = 0]

Pane:

An application-specific window that is managed by a CSplitterWnd. A pane is usually a CView-derived object, but in fact can be any CWnd object that has the appropriate child window ID.

To do so, simply pass the RUNTIME_CLASS of your CWnd derived class as you would if you were using a CView derived class. Your class must use DECLARE_DYNCREATE and IMPLEMENT_DYNCREATE — the framework uses dynamic creation at runtime. Although there is a lot of code that is CView specific in CSplitterWnd, CObject::IsKindOf is always used before those actions are performed. Certainly, it is much easier to use CSplitterWnd with CView derived classes than CWnd derived classes.

Splitter Bar:

A control that is placed between rows and columns of panes. It may be used to adjust the sizes of rows or columns of Panes.

Splitter Box:

A small control at the top of the vertical scroll bars or to the left of the horizontal scroll bars in a dynamic CSplitterWnd. Used to create new rows or columns of panes.

Splitter Intersection:

The intersection of a vertical splitter bar and a horizontal splitter bar. May be dragged to adjust the size of a row and column of panes simultaneously.

The CSplitterWnd class also supports shared scroll bars. These scroll bar controls are children of the CSplitterWnd and are shared with the different panes in the splitter.

For example, in a 1 row x 2 column window, you can specify WS_VSCROLL when creating the CSplitterWnd. A special scroll bar control will be created that is shared between the two panes.

[      ][      ][^]
[pane00][pane01][|]
[      ][      ][v]

When the user moves the scroll bar, WM_VSCROLL messages will be sent to both views. When the views set the scroll bar position, the shared scroll bar will be set.

Note that shared scroll bars are most useful with dynamic or static splits, splitting similar view objects. If you mix views of different types in a splitter, then you may have to write special code to coordinate their scroll positions. Any CView-derived class that uses the CWnd scroll bar APIs will delegate to the shared scroll bar if it exists. The CScrollView implementation is one such example of a CView class that supports shared scroll bars. Non-CView derived classes, classes that rely on noncontrol scroll bars, or classes that use standard Windows implementations (for example, CEditView) will not work with the shared scroll bar feature of CSplitterWnd.

For each row there is a minimum row height, and similarly for each column there is a minimum column width. This minimum is used to decide if the pane is to small to be shown in complete detail.

For a static splitter window, the initial minimum row height and column width is 0. For a dynamic splitter window, the initial minimum row height and column width are set by the sizeMin parameter to the CSplitterWnd::Create function.

These minimum sizes can be changed with the SetRowInfo and SetColumnInfo APIs.

The layout of the panes in the splitter window depends on the size of the containing frame (which in turn resizes the CSplitterWnd. CSplitterWnd repositions and resizes the panes so that they fit as ideally as possible).

The row height and column width sizes set by the user, or through the CSplitterWnd API, represent the ideal size. The actual size can be smaller than that ideal size (if there is not enough room to make that pane the ideal size) or larger than the ideal size (if that pane must be made larger to fill the left-over space on the right or bottom of the splitter window).

The following describes some of the splitter window implementation overridables that can be used by advanced users of CSplitterWnd to customize the features and user interface of this class. These APIs are officially undocumented and are subject to change in future versions of MFC. Refer to the implementation source code for more details on these implementation APIs.

Drawing the splitter bars, boxes and trackers:

enum ESplitType 
    { splitBox, splitBar, splitIntersection, splitBorder };
virtual void OnDrawSplitter(CDC* pDC, ESplitType nType, const CRect& rect);
virtual void OnInvertTracker(const CRect& rect);

These virtual function can be overridden to provide alternate imagery for the various graphical components of a splitter window. The default imagery is similar to the splitter in Microsoft Works for Windows: only intersections of splitter bars are blended together. The imagery is also quite different when the framework detects Windows 4.0 — in order to match the visuals in the shell on that (future) operating system.

Creating controls and views:

virtual BOOL CreateScrollBarCtrl(DWORD dwStyle, UINT nID);

This is called to create a shared scroll bar control. It can be overridden to include extra controls next to a scroll bar. The default behavior is to just create normal Windows scroll bar controls.

virtual void DeleteView(int row, int col);
virtual BOOL SplitRow(int cyBefore);
virtual BOOL SplitColumn(int cxBefore);
virtual void DeleteRow(int row);
virtual void DeleteColumn(int row);

These functions are called to implement the logic of the dynamic splitter window (that is, if the splitter window has the SPLS_DYNAMIC_SPLIT style). They can be customized, along with the virtual function CreateView, to implement more advanced dynamic splitters.

The following are high level commands that are used by the CView class to delegate to the CSplitterWnd implementation. They are virtual so that the standard CView implementation will not require the entire CSplitterWnd implementation to be linked in. For applications that use CView but not CSplitterWnd, the CSplitterWnd implementation will not be linked with the application.

virtual BOOL CanActivateNext(BOOL bPrev = FALSE);

Checks to see if the "Next Pane" or "Previous Pane" command is currently possible.

virtual void ActivateNext(BOOL bPrev = FALSE);

Performs the "Next Pane" or "Previous Pane" command.

virtual BOOL DoKeyboardSplit();

Performs the keyboard split command, usually "Window Split".

Community Additions

ADD
Show:
© 2014 Microsoft