Introduction
The idea of this project came to me when I tried to implement a project using a large amount of splitter views. I wanted to make my splitter views generic but the problem is the impossibility of passing arguments to the constructor of a class when using dynamic creation. More precisely, in my context, I am using the CSplitterWnd::CreateView()
to create and replace views. This method uses the runtime class of a view, to dynamically instantiate a view object and thus one cannot pass an argument to its constructor. This prevents from implementing a generic splitter class creating a splitter view with views (or runtime classes of views) passed as arguments to its constructor. To overcome the problem, I used templates instead.
Using the Code
Before explaining the code, I would like to point out that I have reduced it to the working minimum. This sample is a showcase for using templates and not a finished solution. CMySplitterView
, declared in mysplitterview.h, is the main template class responsible for creating a splitter view with 2 views. The template arguments TView1
and TView2
are the views to show in the splitter view, while TSplitterType
is the type of splitter view created.
template<class TView1, class TView2, class TSplitterType>
class CMySplitterView : public CView
The type defines the layout of the splitter view: horizontal or vertical. Two policy classes define the behaviour:
class CHSplitterType : public CObject
class CVSplitterType : public CObject
Each of these classes define the method CreateSplitterView()
called by CMySplitterView::OnCreate()
to create the splitter view with the specific layout. Moreover, they define OnSize()
called by CMySplitterView::OnSize()
to set the default size of the views. This part of the code could be very much improved. For example, the views used by the template splitter class could expose a method called by OnSize()
to get their desired default size.
Now, to make this work, one will need to define the splitter
classes used within the code. In the sample, I have used two splitter
views: one for the right horizontal splitter
view and one for the global vertical splitter
view (all of the views are CSplitterView
).
template class CMySplitterView<CSplitterView, CSplitterView, CHSplitterType>;
template class CMySplitterView<CSplitterView, tclRightView, CVSplitterType>;
Here, tclRightView
is a type definition for the right horizontal splitter
view CMySplitterView<CSplitterView, CSplitterView, CHSplitterType>
.
For the creation of the main view, I pass tclDefaultView
, a type definition for CMySplitterView<CSplitterView, tclRightView, CVSplitterType>
, to the constructor CSingleDocTemplate()
. Using the type definitions, one can imagine any possible combination of 2-view splitter
views.
Points of interest
Now comes a little tricky part of the sample. Of course, you will need to use IMPLEMENT_DYNCREATE
and BEGIN_MESSAGE_MAP
for your splitter
views. Microsoft provides macros for classes with one or two templates (IMPLEMENT_DYNCREATE_T
, IMPLEMENT_DYNCREATE_T2
…). Unfortunately, these macros are buggy and there are no macros for classes with 3 templates. I have included them in mysplitterview.cpp: M_IMPLEMENT_DYNCREATE_T3
and M_BEGIN_MESSAGE_MAP_T3
and the helper macros M_IMPLEMENT_RUNTIMECLASS_T3
and M_RUNTIME_CLASS_T3
. They work for classes with 3 templates. Here is how to use them:
M_IMPLEMENT_DYNCREATE_T3( CMySplitterView, CSplitterView,
CSplitterView, CHSplitterType, CView )
M_BEGIN_MESSAGE_MAP_T3( CMySplitterView, CSplitterView,
CSplitterView, CHSplitterType, CView )
ON_WM_SIZE()
ON_WM_CREATE()
END_MESSAGE_MAP()
License
This article has no explicit license attached to it, but may contain usage terms in the article text or the download files themselves. If in doubt, please contact the author via the discussion board below.
A list of licenses authors might use can be found here.