Erstellen eines Dialogfelds im Registerkartenbett
Das Beispiel in diesem Abschnitt veranschaulicht das Erstellen eines Dialogfelds, das Registerkarten verwendet, um mehrere Seiten von Steuerelementen bereitzustellen. Das Hauptdialogfeld ist ein modales Dialogfeld. Jede Seite von Steuerelementen wird durch eine Dialogfeldvorlage definiert, die über den WS _ CHILD-Stil verfügt. Wenn eine Registerkarte ausgewählt ist, wird ein modusloses Dialogfeld für die eingehende Seite erstellt, und das Dialogfeld für die ausgehende Seite wird zerstört.
Hinweis
In vielen Fällen können Sie dialogfelder mit mehreren Seiten mithilfe von Eigenschaftenblättern einfacher implementieren. Weitere Informationen zu Eigenschaftenblättern finden Sie unter Informationen zu Eigenschaftenblättern.
Die Vorlage für das Hauptdialogfeld definiert einfach zwei Schaltflächensteuerelemente. Beim Verarbeiten der WM _ INITDIALOG-Nachricht erstellt die Dialogfeldprozedur ein Registerkartensteuerelement und lädt die Dialogfeldvorlagenressourcen für jedes untergeordnete Dialogfeld.
Wichtige Informationen
Technologien
Voraussetzungen
- C/C++
- Windows Benutzeroberfläche-Programmierung
Instructions
Dialogfeld "Create a Tabbed" (Erstellen eines Dialogfelds im Registerkartenbett)
Die Informationen werden in einer anwendungsdefinierten Struktur namens DLGHDR gespeichert. Mithilfe der SetWindowLong-Funktion wird dem Dialogfeldfenster ein Zeiger auf diese Struktur zugeordnet. Die -Struktur wird wie folgt in der Headerdatei der Anwendung definiert.
#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;
Die folgende Funktion verarbeitet die WM _ INITDIALOG-Nachricht für das Hauptdialogfeld. Die -Funktion ordnet die DLGHDR -Struktur zu, lädt die Dialogfeldvorlagenressourcen für die untergeordneten Dialogfelder und erstellt das Registerkartensteuerelement.
Die Größe jedes untergeordneten Dialogfelds wird von der DLGTEMPLATEEX-Struktur angegeben. Die Funktion untersucht die Größe der einzelnen Dialogfelder und verwendet das Makro für die TCM _ ADJUSTRECT-Nachricht, um eine geeignete Größe für das Registerkartensteuerelement zu berechnen. Anschließend wird die Größe des Dialogfelds angepasst, und die beiden Schaltflächen werden entsprechend positioniert. In diesem Beispiel wird TCM _ ADJUSTRECT mithilfe des TabCtrl _ AdjustRect-Makros gesendet.
// 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);
}
Die folgende Funktion verarbeitet den TCN _ SELCHANGE-Benachrichtigungscode für das Hauptdialogfeld. Die Funktion zerstört ggf. das Dialogfeld für die ausgehende Seite. Anschließend wird die CreateDialogIndirect-Funktion verwendet, um ein modusloses Dialogfeld für die eingehende Seite zu erstellen.
// 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;
}
Die folgende Funktion verarbeitet die WM _ INITDIALOG-Nachricht für jedes der untergeordneten Dialogfelder. Sie können die Position eines Dialogfelds, das mit der CreateDialogIndirect-Funktion erstellt wird, nicht angeben. Diese Funktion verwendet die SetWindowPos-Funktion, um das untergeordnete Dialogfeld im Anzeigebereich des Registerkartensteuerelements zu positionieren.
// 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;
}