Yes, it's yet another splitter window class. So why I release a new
class, when there are a plenty of similar classes? The answer is simple. All
splitter window classes at CodeProject can be IMHO divided into two parts:
These derived from original MFC
CSplitterWnd. They look nice and
give a lot of advantages to classical
CSplitterWnd, but deriving
CSplitterWnd restrict you to use only
windows in it.
The others, which I can use in various windows - but when I compiled and tested
them, they didn't look as pretty as the
In this article I offer a class, which is not derived from
It allows you to use simple
CWnd-derived windows. But it's
combined with professional looking of the original
Some routines I took from MFC source code. Please be forbearing while reading
this article. It's my first article at CodeProject :).
My goal in
CSimpleSplitterWnd design was to simulate the basic
CSplitterWnd. With this class you can make several
panes arranged either horizontally or vertically. It doesn't offer automatic
splitting, shared scroll bars and intersection trackers. I didn't find it very
useful - but if there are enough people, who did, I can add some of
these features :) The idea of
CSimpleSplitter (compared to
is that pane windows are independent to each other, hence they are also
responsible for their scrolling and borders.
Using the code
The layout of splitter is set in constructor:
CSimpleSplitter(int nPanes, UINT nOrientation = SSP_HORZ,
int nMinSize = 30, int nBarThickness = 3);
nPanes is number of the panes,
nOrientation should be
the minimal height (or width) of any pane - it is important in recalculating
layout algorithm, when you resize the splitter.
height or width of bars between panes. All of these properties remain fixed
during lifetime of the splitter instance. The creation of splitter and its
panes is straightforward:
BOOL Create(CWnd* pParent, UINT nID = AFX_IDW_PANE_FIRST);
BOOL CreatePane(int nIndex, CWnd* pPaneWnd, DWORD dwStyle,
DWORD dwExStyle, LPCTSTR lpszClassName = NULL);
Panes are indexed from
nPanes - 1. The parameters
pPaneWnd->CreateEx() (If you want to bind a created
window with a pane, use
SetPane instead). You can specify for
example the borders of panes there. In demo app, the "large" panes have a
extended style, while the three "flat" panes have
extended style. The splitter bar alone is only a gray rectangle, so if you
don't specify any edge and set the gray background to pane windows, you can use
the splitter in dialogs too.
The following five methods are analogous to
so they don't require a special documentation.
int GetPaneCount() const;void SetPane(int nIndex, CWnd* pPaneWnd);
CWnd* GetPane(int nIndex) const;
virtual void SetActivePane(int nIndex);
CWnd* GetActivePane(int* pIndex) const;
However, setting the pane widths or heights uses different technique:
void SetPaneSizes(const int* sizes);
You pass an array of
nPanes integers. They specify relative sizes
of panes. You can use any scale, the panes are resized proportionally to the
sum of the array members. When you resize the whole splitter, the sizes of
panes are changed proportionally to their actual sizes. If necessary, they're
void GetPaneRect(int nIndex, CRect& rcPane) const;
void GetBarRect(int nIndex, CRect& rcBar) const;
With these functions you can retrieve the position of panes in splitter client
coordinates. Bars are indexed from
nPanes - 1.
And that's all. Look at the SimpleSplitterApp demo, especially the
code, you will know everything!
Points of Interest
When I programmed the splitter, I was confused, how the framework redraws
resized window. If you resize the top or left border, the framework first only move
the window content in corresponding direction, and then it calls
So the window was redrawn twice and in the splitter this looked ugly.
Fortunately, there is a message handler
You can avoid the initial moving of content, if you see
as you see in
CChildWnd code. I
think that this is useful in many other cases that splitters.
- 11. 2. 2004 - First version released
- 24. 3. 2004 - Some bugs fixed (see the messages below). In the
function now you should pass only relative sizes, not absolute.