MDI Splitter Pane
This article was inspired by some requirements that I have come across for some time now. The requirements are usually to have multiple child windows (most frequently dialogs) displayed as children of another window, maintaining the child windows' proper activation and ability to organize children by tiling or cascading, similar to the way as windows of an MDI application. The last one was specifically requesting a splitter pane with the above-mentioned functionality. The catch is that the application is SDI.
I started with trying to do it in a frame window, but quickly concluded that continuing this way is against my MEMC* standard. Then it came to me: Create a window that is very visible but obscure and nobody pays any attention to it.
In many cases, it is mistaken for a background of the MDI application's main window client area. It is a special window that is not MFC related. It is created by using a special Windows class called "MDIClient". All child windows (frames) of the MDI application belong to that window, not the main frame.
A MDI client window maintains MDI children; it is responsible for tiling and cascading, arranging icons, and activating/deactivating children. In an MDI application, the MDI client is a child of the top-level window. What if I use this special window as a child of another child?
That is how this sample came to life without going against the MEMC* standard.
A pane of the static splitter window is created by calling the CreteView member. The name of this function is misleading because any CWnd-derived window can be used. In the sample, the MDI type of pane is created by passing runtime information about the CPaneFrame - CMDIFrameWnd derived class.
The OnCreateClient member CPaneFrame creates an MDI client passing the "mdiclient" class as one of the creation parameters. It also assigns a special ID for that window; that, is AFX_IDW_PANE_FIRST.
AFX_IDW_PANE_FIRST is very crucial for an MFC implementation of the layout of child windows in the frame. After all other windows (including toolbar and status bar) are positioned, the window with the AFX_IDW_PANE_FIRST ID takes the leftover area of the client of the main frame. In the sample, toolbars and status bar are not used, even though they can be used.
This step is the only one to finalize a preparation for creating MDI children. As you can see, the only override in the CPaneFrame class is OnCreateClient.
MDI child windows
The next step is just a demonstration of how to create MDI pane child windows. Look at the end of InitInstance of the application. In a real application, this call (or a similar one) would be used in different places depending on the design.
There are three additional classes added to the project: CPaneFormView, CPaneEditView, and CPaneDialogView. The first two are views that, by design, will be added to a document and will be able to participate in the MFC updating mechanism, using the UpdateAllViews document member. The sample illustrates it simply by exchanging text typed into edit view or edit control. The last class is a demonstration of using a CFormView-derived class to serve as a dialog.
Command routing changes
Another vital change is to slightly alter command message routing. A splitter window reroutes a command message in the OnCmdMsg virtual override to make sure a MDI pane (frame) has a chance to crack messages too.
Possible Future Enhancements
- Adding the ability to change the menu in a main frame window upon activating different children of the MDI pane.
- Changing the display of a maximized child window to the same as in an MDI application. This calls for additional buttons in a non-client area of the main frame to allow restoring the maximized window to its previous size.
More tests are needed to find any lurking bugs because the MDI client window is working in a different setup. I have tested the app in XP Pro and Vista.
This is only a sample that is designed to show a general approach to fulfill the requirements stated at the beginning of this article. It can be treated as a tutorial and by no means has it presented an ultimate approach to showing how to use an MDI client window outside an MDI application. My goal was to show certain techniques in programming, usinga framework to do most of the work, with minimal code changes needed to reach the goal.
About the Sample Project
The sample code contains source and project files for Visual Studio 2005 and project files for VS 6.0.
* MEMC is an acronym that stands for Maximum Effect [with] Minimum Coding. It was born a long time ago when I tried to describe how to use the MFC framework with minimal changes or additions to the original code.