创建一个标签式对话框

【勇芳软件工作室】汉化HomePreviousNext

本节中的示例将创建一个对话框,该对话框使用选项卡来提供多页控件。主对话框是一个模态对话框。控件的每一页由指定WS_CHILD样式的对话框模板定义。当选择选项卡时,该示例为传入页面创建无模式对话框,并销毁出站页面的对话框。

注意在许多情况下,您可以通过使用属性表更容易地实现多页面对话框。有关属性表的详细信息,请参阅物业单.

主对话框的模板简单地定义了两个按钮控件。处理WM_INITDIALOG消息时,对话框过程将创建一个选项卡控件,并加载每个子对话框的对话框模板资源。

信息保存在一个名为DLGHDR的应用程序定义的结构中。指向此结构的指针通过使用SetWindowLong功能与对话框窗口相关联。结构在应用程序的头文件中定义如下。

#define C_PAGES 3

typedef struct tag_dlghdr {

HWND hwndTab; //标签控件

HWND hwndDisplay; //当前子对话框

RECT rcDisplay; //显示标签控件的矩形

DLGTEMPLATE *apRes[C_PAGES];

} DLGHDR;

以下功能处理主对话框的WM_INITDIALOG消息。该函数分配DLGHDR结构,加载子对话框的对话框模板资源,并创建选项卡控件。

每个子对话框的大小由DLGTEMPLATE结构指定。该函数检查每个对话框的大小,并使用TCM_ADJUSTRECT消息的宏来计算标签控件的适当大小。然后它对齐对话框并相应地定位两个按钮。此示例使用TabCtrl_AdjustRect宏发送TCM_ADJUSTRECT。

VOID WINAPI OnTabbedDialogInit(HWND hwndDlg)

{

DLGHDR *pHdr = (DLGHDR *) LocalAlloc(LPTR, sizeof(DLGHDR));

DWORD dwDlgBase = GetDialogBaseUnits();

int cxMargin = LOWORD(dwDlgBase) / 4;

int cyMargin = HIWORD(dwDlgBase) / 8;

TC_ITEM tie;

RECT rcTab;

HWND hwndButton;

RECT rcButton;

int i;

//保存指向DLGHDR结构的指针。

SetWindowLong(hwndDlg, GWL_USERDATA, (LONG) pHdr);

//创建标签控件。

InitCommonControls();

pHdr->hwndTab = CreateWindow(

WC_TABCONTROL, "",

WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE,

0, 0, 100, 100,

hwndDlg,NULL,g_hinst,NULL

);

if (pHdr->hwndTab == NULL) {

//处理错误

}

//为三个子对话框中的每一个添加一个选项卡。

tie.mask = TCIF_TEXT | TCIF_IMAGE;

tie.iImage = -1;

tie.pszText = "First";

TabCtrl_InsertItem(pHdr->hwndTab, 0, &tie);

tie.pszText = "Second";

TabCtrl_InsertItem(pHdr->hwndTab, 1, &tie);

tie.pszText = "Third";

TabCtrl_InsertItem(pHdr->hwndTab, 2, &tie);

//锁定三个子对话框的资源。

pHdr->apRes[0] = DoLockDlgRes(MAKEINTRESOURCE(DLG_FIRST));

pHdr->apRes[1] = DoLockDlgRes(MAKEINTRESOURCE(DLG_SECOND));

pHdr->apRes[2] = DoLockDlgRes(MAKEINTRESOURCE(DLG_THIRD));

//确定所有子对话框的边界矩形。

SetRectEmpty(&rcTab);

for (i = 0; i < C_PAGES; i++) {

如果(pHdr-后{989 796 004} {989 796 010} - > > rcTab.right CX)

rcTab.right = pHdr->apRes[i]->cx;

如果(pHdr- {989 796 004} {后989 796 012} - > > CY rcTab.bottom)

rcTab.bottom = pHdr->apRes[i]->cy;

}

rcTab.right = rcTab.right * LOWORD(dwDlgBase) / 4;

rcTab.bottom = rcTab.bottom * HIWORD(dwDlgBase) / 8;

//计算制表符控制的大小,所以

//显示区域可以容纳所有的子对话框。

TabCtrl_AdjustRect(pHdr->hwndTab, TRUE, &rcTab);

OffsetRect(& rcTab,cxMargin - rcTab.left,

cyMargin - rcTab.top);

//计算显示矩形。

CopyRect(&pHdr->rcDisplay, &rcTab);

TabCtrl_AdjustRect(pHdr- > hwndTab,FALSE,& pHdr- > rcDisplay);

//设置标签控件的大小和位置,按钮,

//和对话框。

SetWindowPos(pHdr- > hwndTab,NULL,rcTab.left,rcTab.top,

rcTab.right - rcTab.left,rcTab.bottom - rcTab.top,

SWP_NOZORDER);

//移动标签控件下面的第一个按钮。

hwndButton = GetDlgItem(hwndDlg, BTN_CLOSE);

SetWindowPos(hwndButton,NULL,

rcTab.left,rcTab.bottom + cyMargin,0,0,

SWP_NOSIZE | SWP_NOZORDER);

//确定按钮的大小。

GetWindowRect(hwndButton, &rcButton);

rcButton.right -= rcButton.left;

rcButton.bottom -= rcButton.top;

//将第二个按钮移到第一个按钮的右侧。

hwndButton = GetDlgItem(hwndDlg, BTN_TEST);

SetWindowPos(hwndButton,NULL,

rcTab.left + rcButton.right + cxMargin,

rcTab.bottom + cyMargin,0,0,

SWP_NOSIZE | SWP_NOZORDER);

//设置对话框的大小。

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);

//模拟第一项的选择。

OnSelChanged(hwndDlg);

}

// DoLockDlgRes - 加载和锁定对话框模板资源。

//返回指向锁定资源的指针。

// lpszResName - 资源的名称

DLGTEMPLATE * WINAPI DoLockDlgRes(LPCSTR lpszResName)

{

HRSRC hrsrc = FindResource(NULL, lpszResName, RT_DIALOG);

HGLOBAL hglb = LoadResource(g_hinst, hrsrc);

return (DLGTEMPLATE *) LockResource(hglb);

}

以下功能处理主对话框的TCN_SELCHANGE通知消息。该函数会破坏出站页面的对话框(如果有)。然后使用CreateDialogIndirect函数为传入页创建一个无模式对话框。

// OnSelChanged - 处理TCN_SELCHANGE通知。

// hwndDlg - 父对话框的句柄

VOID WINAPI OnSelChanged(HWND hwndDlg)

{

DLGHDR *pHdr = (DLGHDR *) GetWindowLong(

hwndDlg, GWL_USERDATA);

int iSel = TabCtrl_GetCurSel(pHdr->hwndTab);

//销毁当前的子对话框(如果有)。

if (pHdr->hwndDisplay != NULL)

DestroyWindow(pHdr->hwndDisplay);

//创建新的子对话框。

pHdr->hwndDisplay = CreateDialogIndirect(g_hinst,

pHdr->apRes[iSel], hwndDlg, ChildDialogProc);

}

以下功能处理每个子对话框的WM_INITDIALOG消息。您不能指定使用CreateDialogIndirect功能创建的对话框的位置。此函数使用SetWindowPos功能将子对话框定位在选项卡控件的显示区域中。

// OnChildDialogInit - 将子对话框置于下降位置

//在标签控件的显示区域内。

VOID WINAPI OnChildDialogInit(HWND hwndDlg)

{

HWND hwndParent = GetParent(hwndDlg);

DLGHDR *pHdr = (DLGHDR *) GetWindowLong(

hwndParent, GWL_USERDATA);

SetWindowPos(hwndDlg,HWND_TOP,

pHdr- > rcDisplay.left,pHdr- > rcDisplay.top,

0, 0, SWP_NOSIZE);

}