Создание диалогового окна с вкладками
В этом разделе показано, как создать диалоговое окно, использующее вкладки для предоставления нескольких страниц элементов управления. Основное диалоговое окно — это модальное диалоговое окно. Каждая страница элементов управления определяется шаблоном диалогового окна с WS_CHILD стилем. При выборе вкладки создается диалоговое окно без режима для входящей страницы, а диалоговое окно для исходящей страницы уничтожается.
Примечание.
Во многих случаях диалоговые окна с несколькими страницами проще реализовать с помощью листов свойств. Дополнительные сведения о листах свойств см. в разделе "Сведения о листах свойств".
Шаблон для основного диалогового окна просто определяет два элемента управления кнопкой. При обработке сообщения WM_INITDIALOG процедура диалогового окна создает элемент управления табуляции и загружает ресурсы шаблона диалогового окна для каждого дочернего диалогового окна.
Это важно знать
Технологии
Необходимые компоненты
- C/C++
- Программирование пользовательского интерфейса Windows
Instructions
Создание диалогового окна с вкладками
Сведения сохраняются в определяемой приложением структуре с именем DLGHDR. Указатель на эту структуру связан с диалоговым окном с помощью функции SetWindowLong. Структура определена в файле заголовка приложения, как показано ниже.
#define C_PAGES 3
typedef struct tag_dlghdr {
HWND hwndTab; // tab control
HWND hwndDisplay; // current child dialog box
RECT rcDisplay; // display rectangle for the tab control
DLGTEMPLATEEX *apRes[C_PAGES];
} DLGHDR;
Следующая функция обрабатывает сообщение WM_INITDIALOG для основного диалогового окна. Функция выделяет DLGHDR
структуру, загружает ресурсы шаблона диалогового окна для дочерних диалоговых окон и создает элемент управления табуляции.
Размер каждого дочернего диалогового окна определяется структурой DLGTEMPLATEEX . Функция проверяет размер каждого диалогового окна и использует макрос для сообщения TCM_ADJUSTRECT , чтобы вычислить соответствующий размер элемента управления табуляции. Затем он размер диалогового окна и позиционирует две кнопки соответствующим образом. Этот пример отправляет TCM_ADJUSTRECT с помощью макроса TabCtrl_AdjustRect.
// Handles the WM_INITDIALOG message for a dialog box that contains
// a tab control used to select among three child dialog boxes.
// Returns a result code.
// hwndDlg - handle of the dialog box.
//
HRESULT OnTabbedDialogInit(HWND hwndDlg)
{
INITCOMMONCONTROLSEX iccex;
DWORD dwDlgBase = GetDialogBaseUnits();
int cxMargin = LOWORD(dwDlgBase) / 4;
int cyMargin = HIWORD(dwDlgBase) / 8;
TCITEM tie;
RECT rcTab;
HWND hwndButton;
RECT rcButton;
int i;
// Initialize common controls.
iccex.dwSize = sizeof(INITCOMMONCONTROLSEX);
iccex.dwICC = ICC_TAB_CLASSES;
InitCommonControlsEx(&iccex);
// Allocate memory for the DLGHDR structure. Remember to
// free this memory before the dialog box is destroyed.
DLGHDR *pHdr = (DLGHDR *) LocalAlloc(LPTR, sizeof(DLGHDR));
// Save a pointer to the DLGHDR structure in the window
// data of the dialog box.
SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR) pHdr);
// Create the tab control. Note that g_hInst is a global
// instance handle.
pHdr->hwndTab = CreateWindow(
WC_TABCONTROL, L"",
WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE,
0, 0, 100, 100,
hwndDlg, NULL, g_hInst, NULL
);
if (pHdr->hwndTab == NULL)
{
return HRESULT_FROM_WIN32(GetLastError());
}
// Add a tab for each of the three child dialog boxes.
tie.mask = TCIF_TEXT | TCIF_IMAGE;
tie.iImage = -1;
tie.pszText = L"First";
TabCtrl_InsertItem(pHdr->hwndTab, 0, &tie);
tie.pszText = L"Second";
TabCtrl_InsertItem(pHdr->hwndTab, 1, &tie);
tie.pszText = L"Third";
TabCtrl_InsertItem(pHdr->hwndTab, 2, &tie);
// Lock the resources for the three child dialog boxes.
pHdr->apRes[0] = DoLockDlgRes(MAKEINTRESOURCE(IDD_FIRSTDLG));
pHdr->apRes[1] = DoLockDlgRes(MAKEINTRESOURCE(IDD_SECONDDLG));
pHdr->apRes[2] = DoLockDlgRes(MAKEINTRESOURCE(IDD_THIRDDLG));
// Determine a bounding rectangle that is large enough to
// contain the largest child dialog box.
SetRectEmpty(&rcTab);
for (i = 0; i < C_PAGES; i++)
{
if (pHdr->apRes[i]->cx > rcTab.right)
rcTab.right = pHdr->apRes[i]->cx;
if (pHdr->apRes[i]->cy > rcTab.bottom)
rcTab.bottom = pHdr->apRes[i]->cy;
}
// Map the rectangle from dialog box units to pixels.
MapDialogRect(hwndDlg, &rcTab);
// Calculate how large to make the tab control, so
// the display area can accommodate all the child dialog boxes.
TabCtrl_AdjustRect(pHdr->hwndTab, TRUE, &rcTab);
OffsetRect(&rcTab, cxMargin - rcTab.left, cyMargin - rcTab.top);
// Calculate the display rectangle.
CopyRect(&pHdr->rcDisplay, &rcTab);
TabCtrl_AdjustRect(pHdr->hwndTab, FALSE, &pHdr->rcDisplay);
// Set the size and position of the tab control, buttons,
// and dialog box.
SetWindowPos(pHdr->hwndTab, NULL, rcTab.left, rcTab.top,
rcTab.right - rcTab.left, rcTab.bottom - rcTab.top,
SWP_NOZORDER);
// Move the first button below the tab control.
hwndButton = GetDlgItem(hwndDlg, IDB_CLOSE);
SetWindowPos(hwndButton, NULL,
rcTab.left, rcTab.bottom + cyMargin, 0, 0,
SWP_NOSIZE | SWP_NOZORDER);
// Determine the size of the button.
GetWindowRect(hwndButton, &rcButton);
rcButton.right -= rcButton.left;
rcButton.bottom -= rcButton.top;
// Move the second button to the right of the first.
hwndButton = GetDlgItem(hwndDlg, IDB_TEST);
SetWindowPos(hwndButton, NULL,
rcTab.left + rcButton.right + cxMargin,
rcTab.bottom + cyMargin, 0, 0,
SWP_NOSIZE | SWP_NOZORDER);
// Size the dialog box.
SetWindowPos(hwndDlg, NULL, 0, 0,
rcTab.right + cyMargin + (2 * GetSystemMetrics(SM_CXDLGFRAME)),
rcTab.bottom + rcButton.bottom + (2 * cyMargin)
+ (2 * GetSystemMetrics(SM_CYDLGFRAME))
+ GetSystemMetrics(SM_CYCAPTION),
SWP_NOMOVE | SWP_NOZORDER);
// Simulate selection of the first item.
OnSelChanged(hwndDlg);
return S_OK;
}
// Loads and locks a dialog box template resource.
// Returns the address of the locked dialog box template resource.
// lpszResName - name of the resource.
//
DLGTEMPLATEEX* DoLockDlgRes(LPCTSTR lpszResName)
{
HRSRC hrsrc = FindResource(NULL, lpszResName, RT_DIALOG);
// Note that g_hInst is the global instance handle
HGLOBAL hglb = LoadResource(g_hInst, hrsrc);
return (DLGTEMPLATEEX *) LockResource(hglb);
}
Следующая функция обрабатывает код уведомления TCN_SELCHANGE для основного диалогового окна. Функция уничтожает диалоговое окно для исходящей страницы, если таковой есть. Затем она использует функцию CreateDialogIndirect для создания диалогового окна без режима для входящей страницы.
// Processes the TCN_SELCHANGE notification.
// hwndDlg - handle to the parent dialog box.
//
VOID OnSelChanged(HWND hwndDlg)
{
// Get the dialog header data.
DLGHDR *pHdr = (DLGHDR *) GetWindowLongPtr(
hwndDlg, GWLP_USERDATA);
// Get the index of the selected tab.
int iSel = TabCtrl_GetCurSel(pHdr->hwndTab);
// Destroy the current child dialog box, if any.
if (pHdr->hwndDisplay != NULL)
DestroyWindow(pHdr->hwndDisplay);
// Create the new child dialog box. Note that g_hInst is the
// global instance handle.
pHdr->hwndDisplay = CreateDialogIndirect(g_hInst,
(DLGTEMPLATE *)pHdr->apRes[iSel], hwndDlg, ChildDialogProc);
return;
}
Следующая функция обрабатывает сообщение WM_INITDIALOG для каждого дочернего диалогового окна. Нельзя указать позицию диалогового окна, созданного с помощью функции CreateDialogIndirect. Эта функция использует функцию SetWindowPos для размещения дочернего диалогового окна в области отображения элемента управления табуляции.
// Positions the child dialog box to occupy the display area of the
// tab control.
// hwndDlg - handle of the dialog box.
//
VOID WINAPI OnChildDialogInit(HWND hwndDlg)
{
HWND hwndParent = GetParent(hwndDlg);
DLGHDR *pHdr = (DLGHDR *) GetWindowLongPtr(
hwndParent, GWLP_USERDATA);
SetWindowPos(hwndDlg, NULL, pHdr->rcDisplay.left,
pHdr->rcDisplay.top,//-2,
(pHdr->rcDisplay.right - pHdr->rcDisplay.left),
(pHdr->rcDisplay.bottom - pHdr->rcDisplay.top),
SWP_SHOWWINDOW);
return;
}
См. также