| bitbucket: C++ MFC ATL WTL Win32 COM ActiveX Samples Tutorials Source Code Controls |
MultiSplitterWnd |
Download Sample Project |
CMultiSplitWnd is an extended CSplitterWnd MFC implementation, that allows changing number of panes and split orientation on the fly even in a so called "static" splitter.
Features:
How to use:
Instead of CSplitterWnd, dereive from CMultiSplitterWnd. (Since the control does not use it's own message map, you don't even need to change the base class entry in your classes Message Map)
To keep the implementation fairly easy, the following restriction applies:
| AddView | CWnd * AddView(int row, int col, CRuntimeClass * pViewClass, CCreateContext*
pContext = NULL) bool AddView(int row, int col, CWnd * newWnd) Adds a new view, and makes it the current view in the (row, col) pane. The prototype is simular to CSplitterWnd::CreatePane, except for the intial size parameter. You can use the SetRowHeight, SetColWidth, SetPaneSize functions after adding all views. The second prototype allows to add a window that has already been created. The first prottype returns a pointer to the newly created window, or NULL if an error occurs. The second prototype returns true for success, or false if an error occurs. |
||||||
| ShowView | bool ShowView(CWnd * wnd) bool ShowView(CWnd * wnd, int newRow, int newCol) Switch to another view. The view passed in wnd must have been added with AddView before.The second prototype allows moving the view to another pane. |
||||||
| SwitchPanes | void SwitchPanes(int row1, int col1, int row2, int col2) Switch all views that belong to the two given panes 8row1, col1) and (row2, col2). This affects both visible and invisible panes. |
||||||
| GetCurrentView | CWnd * GetCurrentView(int nRow, int nCol) Returns the view currently visible in the given pane. If no view has been created for the pane, or the default background is displayed, this method returns NULL. |
||||||
| RemoveView | bool RemoveView(CWnd * wnd) Removes a view from the splitter window. The window is not destroyed. |
||||||
| SetStaticSplit | void SetStaticSplit(int newRows, int newCols) Change the number of splitters. |
||||||
| ShowDefaultView | void ShowDefaultView(int nRow, int nCol) display the default background in the given pane |
||||||
| IsDefaultView | bool IsDefaultView(int row, int col) Returns true, if the default background is displayed in the given pane. |
||||||
| Pane Sizing |
These functions do what they promise. SetRowheight and SetColWidth return the previous value. Note that SetPaneSize affects the entire row and entire column. |
Switching the Views
The idea was taken from Caroline Engelbienne's article on CodeGuru. To hide a view, its
DlgCtrlID is set to 0, and ShowWindow(SW_HIDE) is called. To show another view,
set the correct DlgCtrlID, and call ShowWindow(SW_SHOW).
The std::map<HWND, POINT> m_map holds the last (or current) pane location
for each view.
The major problem in tuning the CSplitterWnd was the MFC implementation relying on the DlgCtrlID of each pane views to identify the location of each view. Playing around with this caused an epic "ASSERT feast".
Default Background
For empty panes, CMultiSplitterWnd creates a new window for the pane. These windows are
kept in std::map<UINT paneID, HWND wnd> m_defaultPane. To reduce overhead,
default panes are created only when required. The CheckDefaultPane protected
member function verifies for the given pane if the default background needs to be
displayed, and creates the window if necessary.
The default background was used to work around the follwing problem: CSplitterWnd::RecalcLayout
fails with an assertion if no view is visible for a pane. However, RecalcLayout is not
virtual, and is called by many functions; and some uses (like moving multiple view around
in sequence) would require much more coding from the user.
Changing Splitter Count
To do this, the spitter Window is destroyed and re-created with the new row+column count.
To keep the views alive, their parent window is temporary set to the parent of the
splitter itself. (Otherwise, CSplitterWnd::DestroyWindow would destroy the views
as well).
The implementation relies on the internal implementation of CSplitterWnd, but I guess it
isn't likely to change.
5.5.2002: brushed the article up a bit
bitbucket c++ site © Peter Hauptmann. Questions
& Comments to cherea@cherea.de
page updated 29/02/04