Вы находитесь на странице: 1из 10

Лекция 13 Закладки 1

ЛЕКЦИЯ 13
ЗАКЛАДКИ ______________________________________________________________________________ 1
Свойства закладки ______________________________________________________________________ 1
Функции класса CTabCtrl _________________________________________________________________ 2
Создание закладки______________________________________________________________________ 2
Добавление корешка ____________________________________________________________________ 3
Тестирование обработчика изменения активного корешка _____________________________________ 4
Создание страниц закладки ______________________________________________________________ 4
Открытие немодальных дочерних диалогов _________________________________________________ 5
Вычисление положения и размеров страниц ________________________________________________ 6
Отображение страниц закладки ___________________________________________________________ 6
ЛИСТЫ СВОЙСТВ _______________________________________________________________________ 6
Обмен данными с листами свойств ________________________________________________________ 8

ЗАКЛАДКИ
Часто в окне диалога нужно поместить гораздо больше элементов управления, чем оно может вме-
стить. Чтобы решить эту проблему, используются закладки. Они напоминают обычные закладки в книжке.
Кроме того, закладки группируют эти элементы, разделяя их, например, по темам.

Для реализации набора закладок используется класс CTabCtrl. Иерархия классов относительно
CTabCtrl показана на рисунке

CObject

CCmdTaget

CWnd

CTabCtrl
Элемент управления закладка (TAB) позволяет выводить страницы на экран, если пользователь
щелкнул на ее корешке. Можно создать закладку, корешки которой имеют вид кнопок. Чаще всего заклад-
ки используются вместе с листами свойств и создаются автоматически. Каждый корешок закладки может
иметь надпись, значок и 32-битное значение, определяемое приложением.

Свойства закладки
Если закладка создается с помощью редактора диалоговых окон, то на странице свойств Styles дос-
тупны следующие стили:
Multiline корешки закладки будут отображаться в несколько рядов;
Alignment определяет ширину корешков на закладке;
Right Justify (по умолчанию), ширина корешков увеличена чтобы полностью заполнить ряд;
Fixed Width все корешки будут иметь одинаковую ширину;
Ragged Right ширина корешков не увеличивается для полного заполнения ряда;
Buttons корешки будут иметь вид кнопок;

Выжол Ю.А. Программирование на Visual C++


Лекция 13 Закладки 2
Focus определяет, будет ли корешок иметь фокус;
Default корешки не будут иметь фокус;
On Button Down корешок получает фокус, как правило используется для корешков в виде кнопок;
Never корешки не будут иметь фокус;
ToolTips закладка связана с элемент управления “всплывающая подсказка”;
Border набор закладок будет иметь границу;
Bottom корешки будут отображаться внизу набора закладок
Vertical корешки будут отображаться вертикально справа или слева в зависимости от
флага Bottom;

Функции класса CTabCtrl


В классе CTabCtrl определены следующие функции:
Create ( ) создаёт закладку во время выполнения программы;
InsertItem ( ) создаёт новый корешок в закладке;
DeleteItem ( ) удаляет корешок из закладки;
DeleteAllItems ( ) удаляет все корешки из закладки;
AdjustRect ( ) преобразовывает область закладки в клиентскую область и обратно;
RemoveImage ( ) удаляет заданное изображение из списка изображений закладки;
GetImageList ( ) возвращает дескриптор списка изображений;
SetImageList ( ) устанавливает новый дескриптор списка изображений;
GetItemCount ( ) возвращает число корешков;
GetItem ( ) получает информацию о корешке;
SetItem ( ) изменяет информации о корешке;
GetItemRect ( ) возвращает размеры и положение корешка;
SetItemSize ( ) изменяет размер корешка;
GetExtendedStyle ( ) получает дополнительные стили закладки;
GetCurSel ( ) возвращает индекс текущего выбранного корешка;
SetCurSel ( ) устанавливает корешок выбранным;
SetMinTabWidth ( ) устанавливает минимальное значение ширины корешков;
SetPadding ( ) устанавливает размеры поля вокруг значка и надписи корешка;
GetRowCount ( ) возвращает количество строк в закладке ;
GetTooltips ( ) возвращает дескриптор элемента управления “всплывающая подсказка”;
SetTooltips ( ) задает элемент всплывающей подсказки;
GetCurFocus ( ) возвращает индекс корешка, имеющего фокус ввода;
SetCurFocus ( ) устанавливает фокус на заданную корешок;
HighlightIterm ( ) подсвечивает корешок.
Если закладка создается с помощью редактора диалоговых окон, то для выполнения операций с за-
кладками удобно создать с помощью ClassWizard переменную типа CTabCtrl, ассоциированную с эле-
ментом управления “закладка”.

Создание закладки
Закладку можно создать во время выполнения программы. Закладка создаётся в два шага. Сначала
объявляется экземпляр класса с помощью конструктора без параметров CTabCtrl ( ). Удобнее всего это
сделать в интерфейсе класса текущего диалогового окна.
Для создания собственно элемента управления используется функция, которая создает элемент
управления “закладка“ и присоединяет его к объекту класса CTabCtrl. Эту функцию удобно вызывать при
инициализации текущего диалогового окна.
BOOL Create ( DWORD dwStyle , const RECT & rect , CWnd* pParentWnd , UINT nID ) ;
dwStyle стиль закладки;
rect задает расположение и размеры закладки;
pParentWnd задает родительское окно;
nID идентификатор закладки.
Стиль закладки dwStyle может быть суммой нескольких флагов:

Выжол Ю.А. Программирование на Visual C++


Лекция 13 Закладки 3
TCS_BUTTONS корешки будут иметь вид кнопок;.
TCS_FIXEDWIDTH все корешки будут иметь одинаковую ширину;
TCS_FOCUSNEVER корешок не получает фокус.
TCS_FOCUSONBUTTONDOWN корешок получает фокус, как правило используется для корешков в
виде кнопок;
WS_TABSTOP закладка может получить фокус при нажатии клавиши табуляции;
TCS_MULTILINE корешки закладки будут отображаться в несколько рядов
TCS_SINGLELINE отображает только один ряд корешков (по умолчанию);
TCS_FORCELABELLEFT пиктограмма и надпись выравниваются по левому краю корешка;
TCS_FORCEICONLEFT смещает пиктограмму влево и выравнивает название корешка по центру;
TCS_RIGHTJUSTIFY выравнивает корешок по правому краю;
TCS_TOOLTIPS закладка связана с элемент управления “всплывающая подсказка”;
WS_VISIBLE создает видимую закладку;
WS_DISABLED создает закладку, не имеющую доступа;
TCS_RAGGEDRIGHT ширина корешков не увеличивается для полного заполнения ряда;

Добавление корешка
Добавить корешки в закладку можно только во время выполнения программы. Для этой цели служат
четыре перегруженные функции, определённые в классе CTabCtrl:
BOOL InsertItem ( int nItem , LPCTSTR lpszItem ) ;
BOOL InsertItem ( int nItem , LPCTSTR lpszItem , int nImage ) ;
BOOL InsertItem ( int nItem , TCITEM* pTabCtrlItem ) ;
BOOL InsertItem ( UINT nMask , int nItem , LPCTSTR lpszItem , int nImage , LPARAM lParam ) ;
Функции возвращают ноль, если создан новый корешок закладки и –1 в противном случае. Параметры
функций имеют следующее назначение:
nItem индекс нового корешка;
lpszItem указатель на строку названия корешка;
nImage индекс пиктограммы, который хранится в связанном элементе управления типа
CImageList.
lParam определенные приложением данные, связанные с закладкой.
pTabCtrlItem указатель на структуру TCITEM, которая определяет атрибуты корешка;
nMask определяет, какие атрибуты структуры TCITEM используются. Может быть нулем или
комбинацией следующих значений:
TCIF_TEXT используется член структуры pszText;
TCIF_IMAGE используется член структуры iImage;
TCIF_PARAM используется член структуры lParam;
TCIF_STATE используется член структуры dwState;
TCIF_RTLREADING текст pszText читается справа налево.
Созданные корешки будут пронумерованы последовательно, начиная с нуля. Нумерация выполняет-
ся с учётом относительных значений параметра nItem. Корешок, созданный первым, будет активным.
Рассмотрим пример добавления корешков.
создаём проект под именем Demo;
добавляем в диалоговое окно IDD_DEMO_DIALOG элемент управления типа Tab Control с име-
нем IDC_TAB;

Выжол Ю.А. Программирование на Visual C++


Лекция 13 Закладки 4
с помощью ClassWizard создаём переменную m_tab типа CTabCtrl, ассоциированную с элементом
управления IDC_TAB;
добавляем в функцию инициализации диалогового окна класса CDemoDlg вызовы функции вставки
корешков InsertItem ( )
BOOL CDemoDlg :: OnInitDialog ( )
{
CDialog :: OnInitDialog ( ) ;
•••
m_tab.InsertItem(2,"Вторая") ; // создаёт второй корешок с индексом 1 (активный)
m_tab.InsertItem(0,"Первая") ; // создаёт первый корешок с индексом 0
m_tab.InsertItem(4,"Третья") ; // создаёт первый корешок с индексом 2
•••
return TRUE ;
}
Запускаем программу на выполнение. Диалоговое окно должно иметь следующий вид:

Тестирование обработчика изменения активного корешка


Проверим индексацию корешков. Пусть при каждом изменении активного корешка программа выводит
его номер в окне сообщений. Для этого:
открываем макет формы и дважды щелкаем на вкладке;
ClassWizard предложит нам создать обработчик OnSelchangeTab ( ) сообщения
TCN_SELCHANGE, которое вкладка посылает родительскому окну при изменении активного
корешка;

добавляем в тело функции OnSelchangeTab ( ), команды, которые определяют номер активного ко-
решка;
void CDemoDlg :: OnSelchangeTab ( NMHDR* pNMHDR , LRESULT* pResult )
{
CString S ;
S.Format ("%i", m_tab.GetCurSel ( ) ) ;
MessageBox ("Номер активного корешка "+ S ) ;
*pResult = 0 ;
}

Создание страниц закладки


При изменении активного корешка в диалоговом окне отображается новый набор элементов управле-
ния. Эту задачу можно решить путём изменения свойств элементов управления, но это решение крайне
трудоёмко. На практике элементы управления размещают на нескольких диалогах.
Эти диалоги должны отображаться, когда пользователь щелкает на корешках. Листы свойств пред-
ставляют собой особый вид диалогового окна. Они чаще применяются для указания свойств приложения
или каких-либо объектов. Для создания листов свойств надо выполнить следующие действия:

Выжол Ю.А. Программирование на Visual C++


Лекция 13 Закладки 5
добавьте в проект новые диалоговые окна с помощью команды главного меню Insert ► New
Form ... . Их число должно соответствовать количеству создаваемых листов свойств;
задайте диалогам для удобства идентификаторы, так чтобы они были пронумерованы, например:
IDD_PAGE1, IDD_PAGE2 ... ;
задайте классам, соответствующим диалогам, для удобства идентификаторы, так чтобы они были
пронумерованы, например: CPage1, CPage2 ... ;

разместите на каждом диалоге нужные элементы управления;


в окне свойств диалогового окна щелкните на закладке Styles;

в списке Styles выберите значение Child;


в списке Border выберите значение None

Открытие немодальных дочерних диалогов


При работе с закладкой необходимо объявить объекты классов страниц как члены класса CDemoDlg:
class CDemoDlg : public CDialog
{
public:
CTabCtrl m_tab ; // переменная, связанная с элементом управления IDC_TAB
CPage1 m_page1 ; // экземпляр класса первой страницы
CPage2 m_page2 ; // экземпляр класса второй страницы
CPage3 m_page3 ; // экземпляр класса третьей страницы
•••
};
Далее при инициализации текущего диалога (функция OnInitDialog ( )) нужно:
открыть страницы закладки в режиме немодального диалога с помощью функции Create ( ) ;
вычислить положение страниц на текущем диалоговом окне с помощью функции GetPageRect ( ) ;
переместить страницы в вычисленное положение с помощью функции MoveWindow ( ) ;
отобразить страницу по умолчанию с помощью функции ShowWindow ( ).
Перечисленные выше действия реализует следующий код:
BOOL CDemoDlg :: OnInitDialog ( )
{
•••
m_page1.Create ( IDD_PAGE1 ) ; // открывает немодальные диалоги
m_page2.Create ( IDD_PAGE2 ) ;
m_page3.Create ( IDD_PAGE3 ) ;
RECT R = GetPageRect ( m_tab ) ; // вычисляет положение страниц
m_page1.MoveWindow ( &R , FALSE ) ; // перемещает страницы в вычисленное положение
m_page2.MoveWindow ( &R , FALSE ) ;
m_page3.MoveWindow ( &R , FALSE ) ;

Выжол Ю.А. Программирование на Visual C++


Лекция 13 Закладки 6
m_page2.ShowWindow ( SW_NORMAL ) ; // отображает страницу по умолчанию
return TRUE ;
}

Вычисление положения и размеров страниц


Элемент управления “закладка” содержит корешки, границу и клиентскую область. Очевидно, что до-
черние диалоги должны отображаться точно в клиентской области закладки, чтобы не закрывать другие
графические элементы закладки. Вычисление размеров и положения клиентской области не является
тривиальной задачей, поскольку закладка может иметь несколько рядов корешков произвольного размера,
а корешки могут располагаться возле любой стороны закладки. Эту рутинную задачу решает функция Ad-
justRect ( ) (дословный перевод: соответствующий прямоугольник), прототип которой имеет вид:
void AdjustRect ( BOOL bLarger , LPRECT lpRect ) ;
Функции преобразовывает область закладки в клиентскую область и обратно. Параметры функций
имеют следующее назначение:
bLarger определяет направление преобразования. Если параметр равен TRUE, то функция по-
лучает клиентскую область и возвращает область закладки. Если параметр равен
FALSE, то функция получает область закладки и возвращает клиентскую область.
lpRect указатель на прямоугольник, который получает заданных прямоугольник и возвращает
вычисленный;
Для удобства все действия, необходимые для вычисления клиентской области мы поместили в функ-
цию-член класса GetPageRect ( ), которая получает ссылку на объект “закладка” и возвращает размер и
положение клиентской области. Тело функции имеет вид:
CRect CDemoDlg :: GetPageRect ( CTabCtrl &T ) // получает ссылку на объект “закладка”
{
WINDOWPLACEMENT Pos ; // состояние окна закладки
T.GetWindowPlacement ( &Pos ) ; // копирует состояние окна в переменную Pos
CRect Win = Pos.rcNormalPosition ; // получает размер и положение закладки
T.AdjustRect ( FALSE , Win ) ; // вычисляет клиентскую область
return Win ; // возвращает размер и положение клиентской области
}

Отображение страниц закладки


Отобразить выбранную страницу удобнее всего при каждом изменении активного корешка с помощью
обработчика сообщения TCN_SELCHANGE – функции OnSelchangeTab ( ). В тело этой функции мы до-
бавляем следующие операции:
скрываем все страницы;
определяем индекс выбранного корешка;
отображаем соответствующую страницу.
Эти действия реализует следующий код:
void CDemoDlg :: OnSelchangeTab ( NMHDR* pNMHDR , LRESULT* pResult )
{
m_page1.ShowWindow ( SW_HIDE ) ; // скрывает все страницы
m_page2.ShowWindow ( SW_HIDE ) ;
m_page3.ShowWindow ( SW_HIDE ) ;
switch ( m_tab.GetCurSel ( )) // определяет индекс выбранного корешка
{ // отображает соответствующую страницу
case 0: m_page1.ShowWindow ( SW_SHOW ) ; break ;у
case 1: m_page2.ShowWindow ( SW_SHOW ) ; break ;
case 2: m_page3.ShowWindow ( SW_SHOW ) ; break ;
}
*pResult = 0;
}

ЛИСТЫ СВОЙСТВ
Листы свойств позволяют автоматически связать шаблон блока диалога с конкретной страницей за-
кладки. Эти диалоги будут автоматически отображаться, когда пользователь щелкает на закладках. Листы

Выжол Ю.А. Программирование на Visual C++


Лекция 13 Закладки 7
свойств представляют собой особый вид диалогового окна. Они чаще применяются для указания свойств
приложения или каких-либо объектов.
Все необходимые шаги делаются автоматически, если вы добавляете элемент PropertySheet из га-
лереи компонентов. Вам остается только разместить на шаблонах блоков диалога необходимые элементы
управления.
Для добавления элемента PropertySheet из галереи компонентов
выберите пункт меню Project ► Add To Project ► Components and Controls...

в диалоговом окне Components and Controls Gallery Откройте папку Visual C++ Components,
выберите в ней элемент PropertySheet и нажмите кнопку Insert ;
укажите тип будущего листа свойств;

укажите модальный диалог или немодальный;

выберите класс, который будет иметь доступ к листу свойств (как правило, это класс диалогового
окна из которого осуществляется вызов листа свойств);

укажите количество страниц в листе свойств;

укажите имена класса страницы свойств и имена классов страниц;

Выжол Ю.А. Программирование на Visual C++


Лекция 13 Закладки 8

Мастер добавляет подключение заголовочного файла в классе, который использует класс страницы
свойств:
// TabulDlg.cpp : implementation file
•••
#include "MyPropertySheet.h"
Мастер добавляет подключение заголовочных файлов страниц к классу страницы свойств:
// MyPropertySheet.h : header file
•••
#include "MyPropertyPage1.h"
Мастер создаёт объекты страниц как члены класса СMyPropertySheet:
class CMyPropertySheet : public CPropertySheet
{
•••
public:
CMyPropertyPage1 m_Page1 ;
CMyPropertyPage2 m_Page2 ;
•••
};
В конструкторе класса окна свойств мастер вызывает функции AddPage ( ) для добавления вкладок в
окно свойств:
CMyPropertySheet :: CMyPropertySheet ( CWnd* pWndParent )
: CPropertySheet ( IDS_PROPSHT_CAPTION , pWndParent )
{
AddPage ( &m_Page1 ) ;
AddPage ( &m_Page2 ) ;
}

Обмен данными с листами свойств


Для открытия окна с листами свойств мастер добавляет в класс диалогового окна CTabulDlg функ-
цию-член класса OnProperties ( ), реализация которой имеет следующий вид:
void CTabulDlg :: OnProperties ( )
{
CMyPropertySheet propSheet ; // создаёт объект листов свойств
propSheet.DoModal ( ) ; // открывает диалоговое окно с листами свойств
}
Для того чтобы вызвать эту функцию нам нужно подключить её к какому-либо элементу управления,
например к кнопке. Добавляем кнопку IDC_PROP в главное диалоговое окно. Выполняем обработку
щелчка на кнопке IDC_PROP – добавляем или редактируем команду вызова функции OnProperties ( )
при щелчке на кнопке IDC_PROP в карте сообщений:
BEGIN_MESSAGE_MAP ( CTabulDlg , CDialog )
•••
ON_BN_CLICKED ( IDC_PROP , OnProperties )
END_MESSAGE_MAP()
Теперь решим следующую задачу: главное диалоговое окно содержит текстовое поле и флажок:

Выжол Ю.А. Программирование на Visual C++


Лекция 13 Закладки 9
При нажатии кнопки Properties открывается диалоговое окно со страницами свойств, которые также
содержат текстовое поле и флажок:

Если пользователь закрыл окно свойств с помощью кнопки OK, то введённые данные передаются в
главное диалоговое окно.
Для решения этой задачи нужно добавить в главное диалоговое окно элементы управления и с по-
мощью ClassWizard создать ассоциированные переменные категории Value.
// TabulDlg.h : header file
class CTabulDlg : public CDialog
{
•••
public:
BOOL m_flag ; // объявляет переменную член-класса
CString m_text ; // объявляет переменную член-класса
};
// TabulDlg.cpp : implementation file
CTabulDlg :: CTabulDlg ( CWnd* pParent /*=NULL*/) : CDialog ( CTabulDlg :: IDD , pParent )
{
•••
m_flag = FALSE ; // инициализирует переменную член-класса
m_text = _T ("") ; // инициализирует переменную член-класса
}
void CTabulDlg :: DoDataExchange ( CDataExchange* pDX )
{
•••
DDX_Check ( pDX , IDC_FLAG , m_flag ) ; // обмен данными между переменной m_flag
// и элементом управления IDC_TEXT
DDX_Text ( pDX , IDC_TEXT , m_text ) ; // обмен данными между переменной m_text
// и элементом управления IDC_TEXT
}
Добавляем на страницы свойств аналогичные элементы управления. К сожалению, мастеру
ClassWizard классы страниц свойств недоступны. Поэтому необходимые строки можно создать путём ко-
пирования и небольшого редактирования.
Добавляем в класс CMyPropertyPage1 переменную член-класса m_text:
// MyPropertyPage1.h : header file
class CMyPropertyPage1 : public CPropertyPage
{
•••
public:
CString m_text ; // объявляет переменную член-класса
};
Добавляем в класс CMyPropertyPage2 переменную член-класса m_flag:
// MyPropertyPage1.h : header file
class CMyPropertyPage2 : public CPropertyPage
{
•••
public:
BOOL m_flag ; // объявляет переменную член-класса
};
Инициализируем переменную-член класса m_text в конструкторе класса CMyPropertyPage1:
// MyPropertyPage1.cpp : implementation file
CMyPropertyPage1 :: CMyPropertyPage1( ) : CPropertyPage ( CMyPropertyPage1 :: IDD )

Выжол Ю.А. Программирование на Visual C++


Лекция 13 Закладки 10
{
m_text = _T ("Текст") ; // инициализирует переменную член-класса
•••
}
Инициализируем переменную-член класса m_flag в конструкторе класса CMyPropertyPage2:
// MyPropertyPage1.cpp : implementation file
CMyPropertyPage2 :: CMyPropertyPage2( ) : CPropertyPage ( CMyPropertyPage2 :: IDD )
{
m_flag = TRUE ; // инициализирует переменную член-класса
•••
}
Для осуществления автоматического обмена данными между элементом управления IDC_TEXT и
переменной m_text членом класса CMyPropertyPage1 добавляем вызов функции DDX_Text ( ).
// MyPropertyPage1.cpp : implementation file
void CMyPropertyPage1 :: DoDataExchange ( CDataExchange* pDX )
{
CDialog :: DoDataExchange ( pDX ) ;
DDX_Text ( pDX , IDC_TEXT , m_text ) ; // обмен данными между переменной m_text
••• // и элементом управления IDC_TEXT
}
Для осуществления автоматического обмена данными между элементом управления IDC_FLAG и
переменной m_flag членом класса CMyPropertyPage2 добавляем вызов функции DDX_Check ( ).
// MyPropertyPage1.cpp : implementation file
void CMyPropertyPage2 :: DoDataExchange ( CDataExchange* pDX )
{
CDialog :: DoDataExchange ( pDX ) ;
DDX_Check( pDX , IDC_FLAG , m_flag ) ; // обмен данными между переменной m_flag
••• // и элементом управления IDC_FLAG
}
Изменяем тело обработчика щелчка на кнопке IDC_PROP. Теперь функция не только открывает
диалоговое окно с листами свойств, но и считывает значения из элементов управления, расположенных
на странице свойств.
// TabulDlg.cpp : implementation file
void CTabulDlg :: OnProperties ( )
{
CMyPropertySheet propSheet ; // создаёт объект страницы свойств
if ( propSheet.DoModal ( ) == IDOK ) // открывает диалоговое окно с листами свойств
{ // если пользователь закрыл страницу свойств с помощью кнопки OK
m_text = propSheet.m_Page1.m_text ; // передаёт текст, введённый на первой странице
m_flag = propSheet.m_Page2.m_flag ; // передаёт значение флажка со второй страницы
UpdateData ( FALSE ) ; // передаёт данные из переменных-членов класса
} // в ассоциированные элементы управления
}

Выжол Ю.А. Программирование на Visual C++

Вам также может понравиться