Author : Unknown
Page : << Previous 3
XOR operation. With this mode, the tracker can be easily erased if it is drawn twice.
Since we use PATINVERT mode to paint the tracker, its color will become the complement color of red when the user resizes panes using the mouse.
5 Splitter Window That Can't be Resized by Tracking
Sometimes we want each pane of the splitter window to have a fixed size and prevent the user from resizing the panes through using mouse or keyboard. Since dynamic resizing is a built-in feature of class CSplitterWnd, whenever we directly derive a class from it, we will automatically have a resizable split bar. It is not easy to disable this feature because by default, mouse clicking and dragging events will be processed automatically.
In class CSplitterWnd, four mouse messages are handled to change the state of the split bar: mouse left button down message WM_LBUTTONDOWN, mouse left button up message WM_LBUTTONUP, mouse move message WM_MOUSEMOVE, and left button double click message WM_LBUTTONDBLCLK. We need to disable only the first message handler if we want to disable tracking resize feature (Once the application cannot enter the tracking state, the rest messages will be processed normally instead of being treated as part of tracking instructions).
By default, when left button is clicked on a split bar, class CSplitterWnd will respond to this event by letting the user drag the split bar and place it to a new place. We can bypass this feature by overriding WM_LBUTTONDOWN message handler. Instead of calling the message handler implemented by CSplitterWnd, we can call the default function implemented by class CWnd, which is the base class of CSplitterWnd. For a dynamic splitter window, the WM_LBUTTONDBLCLK message handler should not be overridden because after we disable the tracking, double clicking becomes the only way that can be used by the user to dynamically add or delete panes. For WM_MOUSEMOVE and WM_LBUTTONUP messages, we don't need to modify their handlers because after message WM_LBUTTONDOWN is bypassed, the tracking will not happen anymore.
Sample 5\Spw demonstrates how to implement splitter window that cannot be resized through tracking the split bar. It is based on sample 4\Spw.
To let class MCSplitterWnd support both resizable and non-resizable split bars, a new Boolean type variable m_bResizable is declared in the class. Along with this variable a new member function MCSplitterWnd::SetResizable(...) is also declared, which can be called to set m_bResizable flag and indicate if tracking resize feature is currently supported. At the beginning variable MCSplitterWnd::m_bResizable is initialized to TRUE in the constructor. The following code fragment shows the modified class:
(Code omitted)
A WM_LBUTTONDOWN message handler is added to the application. This includes function declaration, adding ON_WM_LBUTTONDOWN message mapping macro, and the implementation of member function. Before adding message mapping, we need to make sure that DECLARE_MESSAGE_MAP macro is included in the class. This will enable massage mapping for the class. The following lists necessary steps for implementing the above message mapping:
1) Declare an afx_msg type member function OnLButtonDown(...) in the class. This function is originally declared in class CWnd, here we must declare it again in order to override it:
class MCSplitterWnd : public CSplitterWnd
{
......
protected:
......
afx_msg void OnLButtonDown(UINT, CPoint);
DECLARE_MESSAGE_MAP()
};
2) In the implementation file, add ON_WM_LBUTTONDOWN macro between BEGIN_MESSAGE_MAP and END_MESSAGE_MAP macros:
BEGIN_MESSAGE_MAP(MCSplitterWnd, CSplitterWnd)
//{{AFX_MSG_MAP(MCSplitterWnd)
//}}AFX_MSG_MAP
ON_WM_LBUTTONDOWN()
END_MESSAGE_MAP()
Macro ON_WM_LBUTTONDOWN maps message WM_LBUTTONDOWN to function OnLButtonDown(...).
3) Implement the message handler as follows:
void MCSplitterWnd::OnLButtonDown(UINT uFlags, CPoint point)
{
if(m_bResizable == TRUE)CSplitterWnd::OnLButtonDown(uFlags, point);
else CWnd::OnLButtonDown(uFlags, point);
}
The function implementation is simple. If the splitter window is trackable, we call CSplitterWnd::OnLButtonDown(...), which will implement tracking if mouse cursor is over the split bar. Otherwise we bypass this feature by calling function CWnd::OnLButtonDown(...).
If the splitter window is created by the Application Wizard, there will be a command View | Split implemented in the application. By default, this command gives an alternate way to resize panes by tracking the split bar. If we want to disable the tracking completely, we also need to disable or remove this menu command.
Summary
1) To implement static splitter window, we need to derive a class from CView (or other type of view classes) for each pane, then declare a CSplitterWnd type variable in class CMainFrame. In function CMainFrame::OnCreateClient(...), we need to call CSplitterWnd::CreateStatic(...) to create the splitter window and call CSplitterWnd::CreateView(...) to attach a view to each pane.
2) Static splitter window can be nested. This means instead of attaching a view, we can use CSplitterWnd to further create splitter window within a pane.
3) Creating dynamic splitter window is simple. In order to do this, we need to declare a CSplitterWnd type variable in class CMainFrame; then in CMainFrame::OnCreateClient(...), we need to call function CSplitterWnd::Create(...).
4) We can override functions CSplitterWnd::DeleteRow(...) and CSplitterWnd::DeleteColumn(...) to customize the behavior of split bars.
5) We can override functions CSplitterWnd::OnDrawSplitter(...) and CSplitterWnd:: OnInvertTracker(...) to customize the appearance of split bar, split box, split border and tracker.
6) To disable split bar tracking, we need to call CWnd::OnLButtonDown(...) instead of CSplitterWnd:: OnLbuttonDown(...) when handling message WM_LBUTTONDOWN.
Page : << Previous 3