Introduction
In a recent project, I wanted to show the document data using different views. I didn't like the default MFC implementation, creating a new frame window for each view.
I headed to Code Project and found several tabbed window articles (Property Sheet View, A Multi Document Tabbed Interface, etc.) but none was exactly what I needed: one frame per document, and one tab per view. With a little help from Google, I found an old article at CodeGuru named "Tabbed Views" by Salvatore Mosaico. I took the original idea, removed the grouping feature, and created this class, adding support for another feature I needed: tool bars and status bars in the child frame.
Using the Code
- Derive a new class from
CTabbedMDIChildWnd
. If you do this by hand, remember to define the message map and dynamic creation. You can use the class wizard to do the dirty work for you.
- Include the header files of your views:
#include "FirstView.h"
#include "SecondView.h"
- To tell the frame window which tabs to use, use the helper class
CTabbedMDIChildWnd::CTabItem
. This class is derived form TCITEM
, with the addition of a CRuntimeClass
to create the view. You can use the provided constructor as in the next example.
- Override
OnCreateClient
. Inside the function, define the tabs, and call the base class:
BOOL CDemoChildWnd::OnCreateClient(LPCREATESTRUCT lpcs,
CCreateContext* pContext)
{
DefineTab(CTabbedMDIChildWnd::CTabItem(_T("First View"),
RUNTIME_CLASS(CFirstView)));
DefineTab(CTabbedMDIChildWnd::CTabItem(_T("Second View"),
RUNTIME_CLASS(CSecondView)));
return CTabbedMDIChildWnd::OnCreateClient(lpcs,pContext);
}
- Your class in now ready. It is a good time to compile the project!
- The next step is to change the MDI child frame inside the
InitInstance
function of the application:
CMultiDocTemplate* pDocTemplate;
pDocTemplate = new CMultiDocTemplate(IDR_TabbedFrameTYPE,
RUNTIME_CLASS(CTabbedFrameDoc),
RUNTIME_CLASS(CDemoChildWnd),
RUNTIME_CLASS(CTabbedFrameView));
AddDocTemplate(pDocTemplate);
Inside the Class
The class has a CTabCtrl
member and creates one tab for each view defined by a call to DefineTab
. It handles the TCN_SELCHANGE
and TCN_SELCHANGING
notify messages to hide and show the views as the tabs are selected.
It uses a std::vector
to keep track of the defined tabs using the runtime class of the different views. This implementation imposes a limitation, only one instance of a view class is supported. Calling DefineTab
several times using the same runtime class is not a good idea!
If you want to change the appearance of the tab control, you can customize CTabbedMDIChildWnd::OnCreateClient
to change the styles of the tab control, or make additional calls to add images, etc.
History
- 1.1 Fixed small memory leak (thanks to J.H.Park)
- 12th March, 2008: Updated downloads