65.9K
CodeProject 正在变化。 阅读更多。
Home

在 MFC 中创建嵌入式对话框

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.70/5 (32投票s)

2003年6月26日

6分钟阅读

viewsIcon

258556

downloadIcon

6428

使用 DS_CONTROL 在 MFC 中创建嵌入式对话框

Sample Image - Embedded_Dialog.gif

引言

最近我们遇到了一个问题,需要在单个属性页或对话框中包含多个对话框。本文将解释我们是如何做到的。

从公司内部流传的讨论来看,这个功能是无休止的混乱和重写的根源。互联网上的各种示例也没有多大帮助,因为它们要求为 CPropertyPageCDialog 类进行自定义派生,并且没有提供良好的键盘用户体验。

本文档记录了使用 MFC 在对话框中提供嵌入式对话框所需的步骤。没有提供扩展类,因为这提供了修改代码以支持嵌入式对话框的技术见解。

背景

将对话框嵌入到属性表或其他对话框中似乎是多年来许多困惑和各种尝试的根源。遗憾的是,我无法找到一个透明且干净的解决方案。网上有各种各样的解决方案,但没有一个具有正确解决方案的外观和感觉。然后我偶然发现了 Microsoft 网站上的文章“Q131283 - PRB: Cannot Use TAB to Move from Standard Controls to Custom”,一切都变得清晰了。

我们需要的解决方案必须简单(它只在一个对话框上),易于使用(对最终用户而言),易于维护(公司中并非所有人都​​是高手)。选择的解决方案是使用一个选项卡条,然后为每个页面使用 CDialog。当选择当前页面时,前一个页面被隐藏,新页面被显示。

虽然这看起来很简单,易于记录,但实施起来却更具挑战性,尤其是在使用键盘进行 Tab 切换方面,这是产品的组成部分。用户需要能够通过 Tab 键进入和退出对话框,同时对话框在主窗口中看起来应该是整体的。

这种设计还允许开发人员使用通用控件 API 在编译时和运行时通过指定图像和选项卡名称等选项来设置选项卡控件。

使用代码

在代码部分,我给出了一个示例,展示了程序员如何在新的对话框中实现两个嵌入式对话框。这些对话框可以通过单击或导航到选项卡控件来选择。请注意,您可以将焦点设置到选项卡控件,然后使用左右箭头选择适当的选项卡,然后使用 Tab 键进入和退出对话框。

首先要做的是创建将嵌入到主对话框中的对话框。这些只是两个直截了当的 CDialog 类。您可以在其中放置任何您喜欢的控件。唯一的要求是,在资源编辑器中对话框属性的“更多样式”选项卡上,对话框样式设置为 Child 和 Control。

建议将框架类型设置为对话框框架。此外,您可以设置对话框相对于其父级的 X 和 Y 位置。要嵌入的对话框应偏移,以便对话框框架顶部显示为选项卡框架底部。当然,这取决于个人喜好和美学。

在示例中,已经创建了两个对话框。文件 Dialog1.hDialog1.cpp 中的 CDialog1 以及 Dialog2.hDialog2.cpp 中的 CDialog2

现在我们已经构建了要嵌入到主对话框中的两个对话框,我们可以创建主对话框了。

我们创建了一个名为 CEmbeddedDialogDlg 的新对话框类,在 EmbeddedDialogDlg.hEmbeddedDialogDlg.cpp 两个文件中实现。嵌入式对话框的实现将在此处进行。

创建对话框后,我们需要为我们之前创建的两个 CDialog 类添加包含,并将它们作为成员添加到 CEmbeddedDialogDlg 类。这些是将插入到 CEmbeddedDialogDlg.h 类中的无模式对话框。

public:
   CDialog2    m_dlg2;
   CDialog1    m_dlg1;

接下来,我们将一个新的选项卡控件资源插入到 CEmbeddedDialog 类的对话框资源中,并子类化此控件,以便于操作。这被添加为 CEmbeddedDialogDlg 类的成员 m_ctlTab1

CEmbeddedDialogDlg 类中唯一需要的功能是 UpdateVisibleWindow 方法,它显示与当前选项卡关联的对话框并隐藏所有其他对话框。当用户更改选项卡控件中的选项卡时,因为它是一个 Windows 通用控件,所以它会生成一个 WM_NOTIFY 消息,其中包含 TCN_SELCHANGE 子消息,表示当前选项卡选择已更改。我们可以使用 CTabCtrl::GetCurSel() 获取当前选项卡选择。这相当于将发送到本机控件的 TCM_GETCURSEL 消息。MFC 只是使其更容易。

拼图的最后一块是 CEmbeddedDialogDlg::OnInitDialog 成员。这是在对话框首次构造但尚未显示之前首次调用的方法。主要的更改部分发生在此处。

此方法的第一步是创建我们将使用的两个选项卡。

   m_ctlTab1.InsertItem(TCIF_TEXT, 0, _T("Dialog1"), 0,0,0,0);
   m_ctlTab1.InsertItem(TCIF_TEXT, 1, _T("Dialog2"), 0,0,0,0);

接下来,我们创建两个对话框的无模式实例,如下所示。

   m_dlg1.Create(CDialog1::IDD, this);
   m_dlg2.Create(CDialog2::IDD, this);

请注意,我们将两个对话框实例的父级设置为 CEmbeddedDialogDlg 对话框,因此所有偏移都将相对于 CEmbeddedDialogDlg 实例。

现在,如果您调用 UpdateVisibleWindow() 并运行项目,您将看到项目正常工作,并且您可以选择不同的选项卡以及使用选项卡控件在对话框之间切换。但是,您会发现选项卡顺序似乎不正确,因为 Tab 切换会将您带到选项卡控件,然后到确定和取消按钮,然后再到嵌入式控件。显然这是不正确和令人困惑的,所以我们需要更改新插入控件的选项卡顺序,使它们在选项卡控件之后正确地进行 Tab 切换。

   m_dlg2.SetWindowPos(GetDlgItem(IDC_TAB1), 0, 0, 0, 0, 
      SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
   m_dlg1.SetWindowPos(GetDlgItem(IDC_TAB1), 0, 0, 0, 0, 
      SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);

为此,我们使用 SetWindowPos 函数并告诉窗口它在选项卡顺序中的位置。请注意,我们已经颠倒了 SetWindowPos 调用的顺序,第一个调用是 CDialog2,然后下一个调用是 CDialog1。这使得代码更容易理解,没有理由不能遵循其他实现。

最后一点需要注意的是,即使它不在代码中,您也应该在 CEmbeddedDialogDlg::DoDataExchange 中调用 m_dlg1m_dlg2DoDataExchange 方法。

关注点

一旦理解了 DS_CONTROL 样式,我惊讶于实现嵌入式对话框是多么容易。整个模型在 Windows 框架内简单轻松地集成,提供了 Microsoft 嵌入式对话框的预期路线的外观和感觉。

历史

根据讨论,我展示了如何添加对 XP 主题的支持。

添加主题支持是一个两步操作。第一步是创建清单文件,可以作为资源嵌入,也可以是带有 yourapp.exe.manifest 文件名的单独文件。如果两者都存在并且您正在运行 XP,则应用程序将采用当前 XP 主题的主题。

第二步是使选项卡与背景颜色相同。这可以通过调用 EnableThemeDialogTexture 并使用 ETDT_ENABLETAB 标志来实现。显然,此可执行文件现在只能在 XP 上运行。

我在 .dsp 文件中添加了两个附加配置,一个名为 Win32 XP Debug,另一个名为 Win32 XP Release。有关主题的优秀文章,请参阅 Microsoft 网站上的使用 Windows XP 视觉样式

© . All rights reserved.