SDI Interface with Multi-Views and Multi-Splitters

Environment: The demo was compiled with Visual C++ 5.0

Overview


For a true SDI application, it is oft necessary to have more than one view.
In most cases, it is also necessary to have splitter windows containing other views.
This sample can be used to implement multi-views in SDI application with or without
splitter. Menu and accelerator table can be changed between views, help ID too.

About this sample


This sample implement 7 views. A standalone CEditView as first view, a splitter
window containing a CTreeView and a CListView, an other splitter window containing
a CView and a CScrollView, a standalone CRichEditView and a standalone CFormView.
The CRichEditView has a new menu with find, next and replace as sample for view
context menu.

Problem creating multi-views and multi-splitters


The framework implement functions to create new views CFrameWnd::CreateView()
and CSplitterWnd::CreateView(). CFrameWnd, uses the AFX_IDW_PANE_FIRST as default
dialog ID for the new view. This ID is used in the RecalcLayout() and if the view
is a standalone view, there is not problem because there is only one view active
with this ID at a time. CSplitterWnd implement a function IdFromRowCol() to
calculate a dialog ID started with AFX_IDW_PANE_FIRST until AFX_IDW_PANE_LAST.
Because there is only 256 possible values for this ID, the splitter limits the
view on a 16×16 matrix. If we want to create a second splitter with other views,
CSplitterWnd::CreateView() fail because the dialog ID exists in the first splitter.

Solution to create multi-splitters


The simple solution for the splitter dialog ID problem is to change the dialog
id of the new created views to zero after creation of all panes so we preserve
the ASSERT message if the programmer try to create an other view at the same
row/column position. To make consistency, we do the same for standalone Views.

Solution to display multi-views and multi-splitters


The framework implements a function to activate views CFrameWnd::SetActiveView()
but not to show or hide other views or splitters. If we want to activate a new view,
we must first hide the actual splitter and views. To preserve the dialog ID
architecture, we must set the dialog ID of hidden splitters and views to zero and
the dialog ID of the active splitter and views to the correct ID i.e. IdFromRowCol()
for views in splitter and AFX_IDW_PANE_FIRST for standalone view.

Implementation


To create new views, it is only necessary to add doc template to the application,
but the resource string must be cleared i.e. containing only the window title
“ViewTitle\n\n\n\n\n\n”. To implement this architecture automatically,
I use a new CSDIDocTemplate class derived from CSingleDocTemplate containing
splitter information (splitter #, row, column). The default constructor set the
splitter # to -1 so to implement a standalone view, we do exactly the same as for
a CSingleDocTemplate. For splitter views, we must give a splitter # different of -1,
the row and column. The new CSDIFrameWnd class derived from CFrameWnd creates the
splitters and views in his CSDIFrameWnd::OnCreateClient() member automatically and
store a view pointer in the doc template for later use. To do this, it uses a new
CSDIWinApp class derived from CWinApp that implement three new little functions
to access these doc templates with view runtime class or view pointer.
The CSDIFrameWnd class has only two user functions.
ActivateView(CRuntimeClass* pViewClass) switch between views and
IsViewActive(CRuntimeClass* pViewClass) to update the user interface.

Menu, Accelerator and Help ID


If you give new menu and accelerator table for the resource IDs in SDIDocTemplate
menu and accelerator table will be changed. The help ID for the view will be changed
according to the resource ID.

Limitation


The number of views or splitters is only limited by memory. Because the two user
functions in CSDIFrameWnd use runtime class, it is not possible to have more than
one view of the same class but normally, it is not a problem. With little change,
you can implement a view ID in the CSDIDocTemplate and use it to switch between
views.

Step by Step


To create an SDI application with multiple views and splitters, do this.

– Create the SDI application with ClassWizard.

– Add SDIApp.* and SDIFrame.* to your project.

– Change the base class CWinApp to CSDIWinApp.

– Change the base class CFrameWin to CSDIFrameWnd.

– Use CSDIDocTemplate instead of CSingleDocTemplate.

– Create new views with ClassWizard.

– Create new resource ID string with new window title, but you can use the same for all new views.

– Create new menu with this resource ID if necessary.

– Add new CSDIDocTemplate in InitInstance() with resource ID, view and splitter number and position.

– In the CMainFrame, add message command to switch between views.

Download demo application – 17 KB

Download demo project – 71 KB

Date Last Updated: February 14, 1999

More by Author

Must Read