CTabsTestDlg - это окно, на котором лежит контрол набора вкладок CTabCtrl. Этот контрол - это родительское окно для всех страниц. Все страницы произведены от класса CMyTabDialog:CDialog, о котором ниже.
Готовый тестовый проект можно взять из по ссылке в конце статьи, но здесь всё равно описаны шаги создания набора вкладок.
Итак, создаём тестовый проект ( MFC, Dialod-based ) с названием TabsTest. Открываем в редакторе ресурсов главное диалоговое окно IDD_TABSTEST_DIALOG. Берём из стандартной палитры элементов управления контрол с названием Tab Control и кладём на диалог. Дадим контролу идентификатор IDC_TAB. Теперь добавим связанный с контролов член-переменную (можно было, конечно, и не делать этого, но так немного удобнее :) ; в общем - добавляем) , нажимая Ctrl+двойной_щелчок_по_контролу. Имя переменной, недолго думая, делаем, приписывая "m_" к идентификатору - m_IDC_TAB. В окошке Category уже указано control , ниже выбираем класс CTabCtrl.
Теперь посмотрим, как вставить вкладки. Сначала немного теории.
Каждая вкладка описана в ресурсе как обычный диалог. Только надо во вкладке Styles свойств ресурса диалога убрать галочку TitleBar , в списке Style выбрать Child, в списке Border выбрать Thin. Ещё нужно сделать диалог невидимым. Также можно удалить вставленные по умолчанию кнопки Ok и Cancel.
Удобно произвести все страницы от своего класса (производного от CDialog), назовём его CMyTabDialog. Удобно это тем, что общий для всех страниц код (например реакция на нажатие Enter или Escape) расположен в одном классе. Кроме того, поскольку страницы будут создаваться динамически, в базовом классе страницы будут сами возвращать в кучу память, отведённую под них:
void CMyTabDialog::PostNcDestroy()
{
CDialog::PostNcDestroy();
delete this;
}
Однако этим мы себя обязали создавать объекты страниц ТОЛЬКО динамически, при помощи оператора new. Причём удалять объекты страниц нужно будет не delete, а вызовом виртуальной функции DestroyWindow().
Пример добавления страницы в проект:
Добавляем в проект страницу page1 :
1) Вставляем новый диалог (дерево ресурсов, Insert Dialog) с идентификатором IDD_page1.
2) Выставляем нужные свойства, убираем кнопки
3) Создаём класс страницы - жмём Ctrl+W , даём название классу CPage1, выбираем базовый класс CDialog.
4) Теперь надо заменить базовый класс на CMyTabDialog.
В дереве классов щёлкаем по классу нашей страницы CPage1, открывается заголовочный файл Page1.h. В строке
class CPage1 : public CDialog
меняем название базового класса с CDialog на CMyTabDialog.
5)Открываем файл реализации Page1.cpp. Перед строкой
вставляем строку
, а также меняем в строке
CPage1::CPage1(CWnd* pParent /*=NULL*/)
: CDialog(CPage1::IDD, pParent)
название базового класса с CDialog на CMyTabDialog.
Итак, пусть имеется 4 страницы с классами CPage1,CPage2,CPage3,CPage4. Они независимы друг от друга и могут содержать свои контролы и различный код.
Далее в программе:
1) добавляем страницы в TabControl
2) удаляем их оттуда
На главном диалоге размещён флажок IDC_chkCREATE для управления этим процессом. В обработчике щелчка CTabsTestDlg::OnchkCREATE() определяем состояние флажка и вызываем либо CTabsTestDlg::CreateProperties() , либо CTabsTestDlg::KillProperties(), в которых происходит создание и удаление объектов вкладок.
Последовательность создания вкладки отражена в макросе def_create_page. Переменная nCurrIndx содержит текущий номер вкладки, после вставки каждой вкладки номер увеличивается.
//макрос - добавление страницы
#define def_create_page(clss,caption) \
{\
clss* pPage=new clss(&m_IDC_TAB);\
item.pszText =(char*)caption;\
item.lParam =(LPARAM)pPage;\
pPage->Create(pPage->IDD,&m_IDC_TAB);\
pPage->SetWindowPos(0, def_DlgTabLef0,def_DlgTabTop0,\
0,0,SWP_NOSIZE|SWP_NOZORDER|SWP_HIDEWINDOW);\
m_IDC_TAB.InsertItem(nCurrIndx, &item);\
nCurrIndx++;\
}
Если требуется удалить вкладку, то при помощи структуры TC_ITEM аналогично вытаскивается указатель на окно вкладки (item.lParam) и для окна вызывается OnDestroy(). В процедуре KillProperties() делается удаление всех вкладок: удаляем первую вкладку до тех пор, пока вкладки ещё есть.
Заметьте, что при закрытии программы можно не заботится об удалении объектов вкладок (если они созданы). Это сделает класс CMyTabDialog.
Теперь нужно сделать переключение страниц, когда пользователь щёлкает по корешкам вкладок. Добавляем в главное окно обработчики событий TCN_SELCHANGE и TCN_SELCHANGING для Tab Control (при помощи визарда - выделите контрол, нажмите Ctrl+W, добавьте нужные обработчики).
//страница, на которую пришли. Показываем её
void CTabsTestDlg::OnSelchangeTab(NMHDR* pNMHDR, LRESULT* pResult)
{
TCITEM item={TCIF_PARAM};
int nTab = m_IDC_TAB.GetCurSel();
m_IDC_TAB.GetItem(nTab,&item);
if(item.lParam)
{
((CWnd*)item.lParam)->ShowWindow(SW_SHOW);
}
*pResult = 0;
}
//страница, с которой ушли. Скрываем её
void CTabsTestDlg::OnSelchangingTab(NMHDR* pNMHDR, LRESULT* pResult)
{
TCITEM item={TCIF_PARAM};
int nTab = m_IDC_TAB.GetCurSel();
m_IDC_TAB.GetItem(nTab,&item);
if(item.lParam)
{
((CWnd*)item.lParam)->ShowWindow(SW_HIDE);
}
*pResult = 0;
}
Вот , в принципе, и всё.
Проект, фрагменты кода из которого приведены в статье, можно найти
здесьУспехов :)