Tabbed Views
First we create a CWnd-derived class
class CTabWnd : public CWnd
{
// Construction
public:
CTabWnd();
// Generated message map functions
protected:
//{{AFX_MSG(CTabWnd)
afx_msg BOOL OnEraseBkgnd(CDC* pDC);
afx_msg void OnPaint();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
}
Then we add a Create function to initialize our control.
BOOL CTabWnd::Create(DWORD dwStyle, CWnd* pParentWnd, UINT nID)
{
CRect rect, parent;
ASSERT(pParentWnd);
if (!CWnd::Create(NULL, "SealiteTabWnd", WS_CHILD|WS_VISIBLE, rect, pParentWnd, nID, NULL))
return FALSE;
m_dwStyle=dwStyle;
return TRUE;
}
As you can see the window is created with an uninitialized rect. It will be resized
as soon as it receives a WM_SIZEPARENT function. It will fill the entire
client area and the views are creating using it as a parent. Because the
control is created in the client area of the parent window it has to draw
itself the client edge. For best results it is recommended that you remove
the WS_EX_CLIENTEDGE style of the parent window.
Next, we add a linked list of views and a CreateView function to add views in it.
typedef struct
{
CWnd *pWnd;
char szLabel[32];
int x_min, x_max;
}
CList <TABWND_MEMBER*,TABWND_MEMBER *> m_viewList;
BOOL CreateView(LPCTSTR lpszLabel, CRuntimeClass *pViewClass, CCreateContext *pContext);
In the CreateView function we instantiate the pViewClass using CRuntimeClass::CreateObject()
and add the resulting CView to the list.
The created views have to be resized whenever the parent window resize, so we add a handler for WM_SIZEPARENT.
LRESULT CTabWnd::OnSizeParent(WPARAM, LPARAM lParam)
{
PostMessage(WM_TABRESIZE);
return 0;
}
To find out
how much space is available for the client area after the control bars
have allocated space for themselves we have to use the RepositionBars function
with the CWnd::reposQuery parameter. Unfortunatly in a WM_SIZEPARENT handler
RepositionBars does not return a valid rectangle because the message is
used by the control bars to resize the client area. To walk around this
we post a message and in its handler we can safely call this function.
The next thing to do is handle the WM_PAINT message to draw the selector and the WM_LBUTTONUP message to switch the views. The SetActiveView function is used to make sure that the window/command messages are routed to the active view. When the current tab is changed both the view thats going to be selected and the one thats going to be unselected are sent the WM_TABCHANGED message.
This is a rather complex subject and it is imposible to throughly cover it in a few pages. For more information you should go through the CTabWnd (you can download the project and source files by clicking the link at the beginning of this page) and CSplitterWnd.
Date Last Updated: April 3, 1999

Comments
There are no comments yet. Be the first to comment!