Objective Toolkit : Chapter 10 MDI Alternatives : Benefits of MDI Alternatives
Benefits of MDI Alternatives
With the release of Windows 95, Microsoft made it known in The Windows Interface Guidelines for Software Design that they are moving away from MDI in their Office products; however Microsoft has not provided Windows operating-system-level support or MFC support for any of the MDI alternatives described in their design guide. Currently, MFC only supports the Multiple Document Interface (MDI) and Single-Document Interface (SDI), which are waning in popularity. Objective Toolkit proves you with three additional alternatives: MTI, FDI, and WDI.
Multiple Top-level Interface (MTI)
MTI is a combination of SDI and MDI. As in SDI, each top-level window manipulates one document. As in MDI, the user can have multiple documents open simultaneously. MTI creates a new top-level window for each new document. MTI departs from the MDI model in which one parent frame owns and contains every document window.
From the user’s standpoint, an MTI application most closely resembles an SDI application because he can only associate one document with a frame.
Figure 86 – Example of a MTI Application
However, note that when the user loads or creates document, an additional frame is created to hold the document instead of loading the document into the existing frame.
Figure 87 – Example of an MTI Application (new document)
MTI-based applications create document windows that float freely on the desktop. This approach is common in other GUI operating systems such as the OSF/Motif windowing system for UNIX. It has also become a popular Windows interface. For example, you can easily activate MTI windows from the Windows 98 taskbar.
MTI Class – SECToplevelFrame
The SECToplevelFrame class is the basis for the MTI MDI-alternative. MTI applications derive from SECToplevelFrame whereas an MDI application would derive from CMDIChildWnd.
The following figure is the hierarchy for SECToplevelFrame.
Figure 88 – Objective Toolkit MTI Class Hierarchy
Using MTI
The following sections describe how to create an MTI application from a new or existing MFC project.
To convert an existing SDI application to MTI
1. Replace the base class of your CFrameWnd-derived class with SECToplevelFrame.
2. Replace the instantiation of a CSingleDocTemplate in the InitInstance() method of your CWinApp-derived class to CMultiDocTemplate.
To convert an existing MDI application to MTI
1. Replace the base class of each existing MDI child frame (CMDIChildWnd) with SECToplevelFrame. This ensures that the MDI child windows retain all of their previous capabilities and can float freely on the desktop instead of being confined to the MDI frame window.
2. Remove the CMainFrame class and all references to it from your application. Because MTI has no equivalent to an MDI frame window, your CMainFrame class has no role in a MTI implementation. If you have a significant amount of code in your CMainFrame class, you need to consider moving the code to a new location.
3. The next step is to modify the OnInitInstance() method of your CWinApp-derived class. The OnInitInstance() method typically includes code to instantiate a document template and the MDI frame window. You must remove the instantiation of the MDI frame window and all references to it from the application.
4. In most cases, it is not necessary to modify the code in OnInitInstance() method which instantiates the document template. The CMultiDocTemplate is still used by MTI because it does not include anything that is MDI-specific. It manages multiple documents (document/view documents, not MDI documents) and, in that capacity, remains useful for MTI without modification.
5. Override the OnCreate() method of your SECToplevelFrame-derived class or classes and create your control bars (toolbars, status bars, and more). CFrameWnd::OnCreate() is the method that usually creates these objects and SECToplevelFrame-derived classes are no exception.
To create a new MTI-based application
1. Create a new MDI application using the Visual C++ | MFC App Wizard.
2. Follow the steps described in “To convert an existing MDI application to MTI”.
Customizing MTI
The following sections show you how to modify the default behavior of an MTI application and present some information about message handling.
To load the document into the initial, empty frame
By default, MTI-based applications behave the same way as MDI apps. For example, when you open a MTI application one top-level frame window containing an empty, untitled document appears. If you select Open from the File menu and select a file, a new top-level window is created, and the document is displayed therein. When you open a file, you are actually opening two windows. One window is empty whereas the other window contains the document of interest. This is exactly the same behavior MDI applications exhibit. In some applications, it is preferable to load the document into the initial empty frame rather than create a new one.
1. Derive a class from CMultiDocTemplate and override its OpenDocumentFile() method.
2. You may also want to change the standard call to the OnFileNew() method in CYourApp::InitInstance() to OnFileOpen() so your application will display an open file instead of an empty document in the first top-level frame when you start it.
Message Dispatching in an MTI Application
There are a couple of key MTI data members that you need to consider if you’re setting up message dispatching for your MTI application:
SECToplevelFrame::s_tlfList. A static list of open top-level frame windows. You may need to dispatch a message or member function call to every top-level frame window on the desktop. Only those owned by the MTI application in question are accessible. Iterate over the top-level frames in this list and dispatch messages to them individually.
NOTE >> If you are using MTI in a DLL, use the accessor functions GetTLFList() and SetTLFList().
theApp.m_pMainWnd. In SDI and MDI applications, only one main frame window is allowed by definition. Consequently, m_pMainWnd is initialized at startup and remains constant until the application exits. With MTI, the m_pMainWnd is constantly changing to reflect the top-level frame that currently has focus. If you need to dispatch a message or member function call to the active top-level frame, reference this variable.
Other Uses For SECToplevelFrame
The SECToplevelFrame class can act as more than a MDI alternative in your application. Because SECToplevelFrame is only varies slightly from CFrameWnd, you can use it anywhere you would have used CFrameWnd as a base class. SECToplevelFrame contains nothing that binds it to the document/view architecture, so you can use it in applications that do not adhere to doc/view architecture. When you use this class as a specialized frame window instead of an MDI alternative, SECToplevelFrame gives you the capability to create a top-level frame with any arbitrary client. The top-level frame is given its own entry in the Windows 98 task bar, and it can remain open when other application windows are iconified.
MTI Sample
The Objective Toolkit mt_scrib sample (<stingray-installdir>\Samples\Toolkit\MFC\MDI\MTScribble) shows how to convert the MFC tutorial, Scribble, from MDI to MTI.
Floating Document Interface (FDI)
FDI is like MDI except in FDI the MDI children can float freely on the desktop. In MDI, the MDI children are confined to the MDI parent window. As with MDI, you can have multiple open documents in FDI. FDI creates a new floating child window for each new document. Each FDI child window appears as a top-level window and manipulates one document. Optionally, each FDI child window can include a menu bar containing menu items specific to that window.
Figure 89 – Example FDI application
As for the main window, all menu items need to apply at the application level or to all FDI children; otherwise, focus becomes an issue. For example, if you activate an FDI child and then pick a menu item from the main application window, the FDI child loses activation and consequently its menu pick. FDI-based applications have a look-and-feel that is similar to Microsoft Visual Basic.
Differences between FDI and MTI
Because FDI allows you to place document windows on the desktop, its interface is somewhat similar to MTI. In MTI, no main window owns all the other windows in the application. However, the concept of a main frame window remains to serve as a menu strip or primary application window. Because MTI document windows are root-level windows, they are given their own Windows 98 task bar entries. FDI document windows are not root-level windows. You can iconify MTI document windows independently of all other windows. In FDI, when the main application window is iconified, all the FDI children are iconified as well.
FDI Classes
FDI is implemented in two classes that both derive from SECFrameWnd. This hierarchy is as follows.
Figure 90 – Objective Toolkit FDI class hierarchy
SECFDIChildWnd
The SECFDIChildWnd class is a document window that is similar to a MDI child window, except it can float freely on the desktop whereas a MDI child window is tied to its parent frame. FDI applications derive from SECFDIChildWnd. MDI applications derive from CMDIChildWnd.
SECFDIFrameWnd
The SECFDIFrameWnd class is a main frame window that adds support for the Window menu and the Windows… dialog. FDI applications derive from SECFDIFrameWnd. MDI application would derive from CMDIFrameWnd.
Using FDI
The following sections tell how to use FDI in new and existing projects.
To convert an existing SDI application to FDI
1. First, convert your SDI application to an MDI application. This transition is typically comprehensive. It may require you to re-derive several of your application’s classes.
2. Follow the steps described in “To convert an existing MDI application to MTI”.
To convert an existing MDI application to FDI
1. Replace CMDIChildWnd, the base class of all existing MDI child frames, with SECFDIChildWnd so that the MDI child windows retain all of their previous capabilities and float freely on the desktop instead of being confined to the MDI frame window.
2. Replace CMDIFrameWnd, the base class of your main frame class, with SECFDIFrameWnd.
3. If you want your main frame window to serve as a menu strip, override SECFDIFrameWnd::PreCreateWindow() and then specify the initial window size and position.
4. Override the OnCreate() method of your SECFDIChildWnd-derived class or classes and create your control bars (toolbars, status bars, and more).
To create a new FDI-based application
1. Generate an MDI application using AppWizard.
2. Follow the steps in “To convert an existing MDI application to FDI”.
FDI Sample
The Objective Toolkit fdi sample (<stingray-installdir>\Samples\Toolkit\MFC\MDI\FDI) illustrates the use of the SECFDIChildWnd and SECFDIFrameWnd classes.
Workbook Document Interface (WDI)
The WDI classes enhance MDI by allowing the user to place every document in a tabbed window. This reduces MDI modality. All of the documents are part of a workbook of worksheets. The user can open a specific worksheet by clicking a tab instead of selecting the Window menu and searching for it.
Figure 91 – Example MDI Application
Because WDI adds an optional Workbook View to MDI, there is no cost associated with converting your MDI application to WDI. WDI enhances your MDI application without losing any functionality or fundamentally changing the MDI user interface. In other words, a WDI application with workbook viewing mode deactivated is equivalent to MDI.
Adding Flat Style Drawing to the Workbook Window
New ‘flat’ style drawing has been added to the workbook window. In order to enable flat style drawing, you need to call the SetFlatStyleMode function (a member of the SECWorkbook class).
Figure 92 – A Workbook Window with Flat Style enabled
To view sample code which shows how to set the flat drawing style, please see the CMainFrame::OnCreate function implementation in MAINFRM.cpp, VIZ sample:
 
SetFlatStyleMode(TRUE);
The Viz sample demonstrates this feature, and can be found at <stingray-installdir>\Samples\Toolkit\MFC\Docking\Viz.
Adding Flat Style Drawing to the Shortcut Window
New ‘flat’ style drawing has been added to the shortcut window. In order to enable flat style drawing, you need to call the SetFlatStyleFunction function (a member of the SECShortcutBar class).
Figure 93 – A Shortcut Window in Mouse Hover mode with Flat Style Enabled
To view sample code which shows how to set the flat drawing style, please see the CShortcutListDockBar::OnCreate function implementation in LSTDBAR.cpp, VIZ sample:
 
m_scListBar.SetFlatStyleMode(TRUE);
The Viz sample demonstrates this feature, and can be found at <stingray-installdir>\Samples\Toolkit\MFC\Docking\Viz.
Adding Flat Style Drawing to the 3D Tab Control Window
New ‘flat’ style drawing has been added to the 3D tab control window. In order to enable flat style drawing, you need to set the TWS_FLATSTYLE window style while creating the tab control window. Alternatively, you can enable flat style drawing at a later time by calling the SetTabStyle function (a member of the SEC3DTabWnd class).
Figure 94 – A 3D Tab Control Window with Flat Style Enabled
To view sample code which shows how to enable flat style drawing for tabbed control windows during creation time, please see the ProjectWorkspaceWnd::OnCreate function implementation in PRJBAR.cpp fo the Viz sample:
 
m_wndTab.Create(this,WS_CHILD|WS_VISIBLE|TWS_TABS_ON_BOTTOM|
TWS_FLATSTYLE);
To view sample code which shows how to toggle flat style drawing for tabbed control windows, please see the CChildFrame2::OnSwitchFlat function implementation in CHLDFRM2.cpp of the TabDemo sample:
 
m_bFlatStyle = !m_bFlatStyle;
DWORD dwStyle = m_tabWnd.GetTabStyle();
if( !m_bFlatStyle )
dwStyle &= (~TWS_FLATSTYLE);
else
dwStyle |= TWS_FLATSTYLE;
m_tabWnd.SetTabStyle( dwStyle );
The TabDemo sample does not ship with the product. For information on where you can obtain this sample, see “Location of Sample Code” in the Getting Started part.
The Viz sample also demonstrates this feature. It can be found in at <stingray-installdir>\Samples\Toolkit\MFC\Docking\Viz directory.
WDI Classes
WDI support is provided by a combination of three MFC extensions: SECWorkbookWnd, SECWorksheetWnd, and SECWorkbookClientWnd.
Figure 95 – Objective Toolkit WDI Class Hierarchy
SECWorkbookWnd
The SECWorkbookWnd class is derived from SECMDIFrameWnd. It adds the workbook interface (WDI) enhancements. Derive your main frame window class from SECWorkbookWnd if you want the workbook interface enhancements.
SECWorksheetWnd
The SECWorksheetWnd class is derived from SECMDIChildWnd. It adds the workbook interface (WDI) enhancements. Derive your MDI child windows from SECWorksheetWnd if you want to implement the workbook interface enhancements.
SECWorkbookClientWnd
The SECWorkbookClientWnd subclasses the MDI client window and is implemented as a part of the workbook interface. SECWorkbookClientWnd allows the WDI framework to hook into CFrameWnd’s window layout calculation and specify a client area that allots space for drawing the border and tabs.
To convert an existing MDI application to WDI
1. Replace CMDIChildWnd, the base class of all existing MDI child frames, with SECWorksheetWnd so the MDI child windows retain all of their previous functionality and become tabbed worksheets.
2. Replace CMDIFrameWnd, the base class of your CMainFrame class, with to SECWorkbookWnd.
3. Replace the base class of all toolbars derived from CToolBar with SECToolBar.
4. Replace CStatusBar, the base class of the status bar, with SECStatusBar.
5. Call SetWorkbookMode(TRUE) in CMainFrame::OnCreate().
Customizing WDI
SECWorkbookWnd has overridable functions that you can use to customize several aspects of WDI including:
The order in which tabs are displayed
The tab label
The tab icon
The interface’s general appearance
To change the tab display order
Override the AddSheet() and RemoveSheet() member functions. These members are expected to assign values to SECWorksheetWnd::m_nPosition for every worksheet in your workbook. In your override, you can assign any tab position to newly created worksheets.
To draw a different worksheet tab label
Override the SECWorkbookWnd::GetTabLabel() function.
To change the icon
Override the SECWorkbookWnd::GetTabIcon() function.
To change the appearance of the tabs
Override the SECWorkbookWnd::OnDrawTab() and SECWorkbookWnd::OnDrawTablconAndLabel() functions.
Key WDI Methods and Data Members
A summary of the key methods and data members that you can use to customize the WDI is presented in the table below.
Table 29 – Key Methods and Data Members for WDI 
Member
Description
SECWorksheetWnd::m_nPosition
A data member that specifies the position of the tab associated with this worksheet within the row of tabs in the workbook. By default, the application display the tabs by order of creation. You can change the order by assigning a value to this member.
SECWorkbookWnd::AddSheet()
A virtual method that is called whenever a new MDI child window is created. This member creates a new tab associated with the new MDI child and assigns it a position within the row of tabs. To change the order in which tabs are displayed, override the AddSheet() member and set the SECWorksheetWnd::m_nPosition member.
SECWorkbookWnd::RemoveSheet()
A virtual method called whenever an MDI child window is destroyed. Override this member if you require additional work to occur whenever a sheet is removed from the workbook.
SECWorkbookWnd::GetTabLabel()
A virtual method that returns the label to be drawn on the tab. By default, this label is the title of the MDI child’s active document. If this label is not appropriate for your application, override this member and return the label you need.
SECWorkbookWnd::GetTabIcon()
A virtual method that returns the icon to be drawn on the tab. If NULL is returned, no icon is drawn. By default, this icon is the one associated with the MDI child frame via the resource file. If you prefer a different icon, override this member and return a different icon.
SECWorkbookWnd::OnDrawTab()
A virtual method that draws a blank tab at the position within the row of tabs specified by SECWorksheetWnd::m_nPosition. By default, the tab has a 3D look. If you want to change the look of the tab, override this member and draw the tab with the look you prefer.
SECWorkbookWnd::OnDrawTabIconAndLabel()
A virtual method that renders the icon and tab label on top of the blank tab drawn by SECWorkbookWnd::OnDrawTab(). Override this member if you require the tab’s inscription to be rendered differently.