Tab control managed using CTabCtrl MFC class is a good replacement candidate for Property Sheets. But these Tab Controls are less used and discussed still less. This article explains how to use the CTabCtrl class for manipulating a Tab Control and hold 2 different dialog boxes. The sample given here can be extended to add more dialog boxes.
The article had been revised to support the child controls inside the dialog boxes placed on the CTabCtrl. There had been a lot of queries from our visitors on this issue. We had not been able to reply to each one of them. Sorry about that. We’ve revised the article.
Creating the Tab Holder Dialog for CTabCtrl:
As a first step for using this tab control, a placeholder dialog needs to be created. This place holder could be a Form View or a Dialog box. This example illustrates CTabCtrl usage with a Dialog box.
- Create an MFC Dialog based application. Modify the Title of the dialog to “Tab control Holder Dialog”. This is to differentiate the parent dialog from the rest of the child dialog boxes.
- Place a Tab Control on the dialog box. The article uses the ID of the tab control as IDC_TABCTRL1.
- A derived class of CTabCtrl has to be created now. This class will handle initializing the tab sheet dialogs, activating each of them at every selection etc.,
Creating the Derived class for CTabCtrl:
- Open the class wizard by pressing the key combination Ctrl + W. Click on the Add Class –> New button. We’ll use this interface to add a derived class for CTabCtrl.
- Enter the name of the derived class (of CTabCtrl ) in the empty text box. This article uses MyTabCtrl as the class name for the derived class. Select the CTabCtrl as the Base Class. Two Files will be created as MyTabCtrl.h and MyTabCtrl.cpp.
- Add the following data and function members to the MyTabCtrl class, in the MyTabCtrl.h file.
//Array to hold the list of dialog boxes/tab pages for CTabCtrl int m_DialogID[2]; //CDialog Array Variable to hold the dialogs CDialog *m_Dialog[2]; //Function to Create the dialog boxes during startup void InitDialogs(); //Function to activate the tab dialog boxes void ActivateTabDialogs();
- Open the class wizard for MyTabCtrl and add a handler for TCN_SELCHANGE event (of CTabCtrl). This can be done through the Class Wizard –> Message Maps tab.
- Open the MyTabCtrl.cpp file and paste the following functions. All these functions except ActivateTabDialogs() and InitDialogs() are simple modifications to the original functions, which were generated by the wizard.
- We will have to include the Child dialog header files in this MyTabCtrl.cpp.
//Constructor for the class derived from CTabCtrl MyTabCtrl::MyTabCtrl() { m_DialogID[0] =IDD_DIALOG1; m_DialogID[1] =IDD_DIALOG2; m_Dialog[0] = new MyDlg1(); m_Dialog[1] = new MyDlg2(); m_nPageCount = 2; } //This function creates the Dialog boxes once void MyTabCtrl::InitDialogs() { m_Dialog[0]->Create(m_DialogID[0],GetParent()); m_Dialog[1]->Create(m_DialogID[1],GetParent()); } //Selection change event for the class derived from CTabCtrl void MyTabCtrl::OnSelchange(NMHDR* pNMHDR, LRESULT* pResult) { // TODO: Add your control notification handler code here ActivateTabDialogs(); *pResult = 0; } void MyTabCtrl::ActivateTabDialogs() { int nSel = GetCurSel(); if(m_Dialog[nSel]->m_hWnd) m_Dialog[nSel]->ShowWindow(SW_HIDE); CRect l_rectClient; CRect l_rectWnd; GetClientRect(l_rectClient); AdjustRect(FALSE,l_rectClient); GetWindowRect(l_rectWnd); GetParent()->ScreenToClient(l_rectWnd); l_rectClient.OffsetRect(l_rectWnd.left,l_rectWnd.top); for(int nCount=0; nCount < m_nPageCount; nCount++){ m_Dialog[nCount]->SetWindowPos(&wndTop, l_rectClient.left, l_rectClient.top, l_rectClient.Width(), l_rectClient.Height(), SWP_HIDEWINDOW); } m_Dialog[nSel]->SetWindowPos(&wndTop, l_rectClient.left, l_rectClient.top, l_rectClient.Width(), l_rectClient.Height(), SWP_SHOWWINDOW); m_Dialog[nSel]->ShowWindow(SW_SHOW); }
- Now the above can be enough for a basic tab control with CTabCtrl, which can be made to hold 2 dialog boxes or tab sheets.
The next step will be to create two dialog boxes which will be used as the Tab sheets.
Creating the Tab Sheets for CTabCtrl:
- Create two Dialog boxes by using the Visual Studio –> Menu –> Insert Resource –> Dialog.
- Ensure that their ids are IDD_DIALOG1, IDD_DIALOG2. The sample in this article uses these IDs marked in Blue.
- Put some controls or some sample text on the dialog boxes for differentiating both of them from each other.
- For both the dialogs, set the Properties Dialog –> Styles –> Style equal to Child.
- Also Un-check the Properties Dialog –> Styles –> Title bar and System Menu. They should be set to false. Because the tab sheets cannot have a title bar.
- Set the Properties Dialog –> More Styles –> Visible style to True.
- For both the dialogs create two dialog classes by using the class wizard.
Initializing and Activating the Tab Sheets in CTabCtrl:
- Open the Parent dialog which holds the Tab Control.
- Open the class wizard.
- In the Class wizard –> Member Variables tab, add a variable for the Tab control. Use the MyTabCtrl as the class representing the Tab Control, instead of CTabCtrl. This sample uses the variable name as m_tbCtrl. The green colored items relate the tab control ID and the member variable for the tab control.
After this, in the OnInitDialog of the same class, add the following lines of code.
m_tbCtrl.InitDialogs(); m_tbCtrl.InsertItem(0,"Sample Tab 1"); m_tbCtrl.InsertItem(1,"Sample Tab 2"); m_tbCtrl.ActivateTabDialogs();
Now the application is ready to be launched. Build the application and execute it. The application will have 2 tab sheets and upon clicking the tab buttons, the dialogs get activated correspondingly.
Do not forget to include the Child dialog header files in the MytabCtrl.cpp.
There will be a small problem if you press ESC key or Enter keys. The tab sheets will disappear. To avoid this refer to, How to avoid closing of the dialog boxes when ESCAPE key or ENTER key is pressed.
The sample program for the above article is available at CTabCtrl Sample.