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

CTreePropSheet - 类似于 Netscape/Visual Studio .NET 的首选项对话框

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.94/5 (140投票s)

2003年2月26日

8分钟阅读

viewsIcon

1087333

downloadIcon

12458

此框架引入了一个属性表,它基于原始的 Windows 属性表(继承自 CPropertySheet),但使用树形控件来浏览页面,而不是选项卡控件。

Content

  1. 引言
    1. 这是什么?
    2. 为什么要再来一个?
    3. 特点
  2. 使用 CTreePropSheet
  3. 自定义 CTreePropSheet
    1. 基础
    2. 高级
      1. 页面框架和标题
      2. 页面树
      3. 空页面消息
  4. 参考
  5. 要求
  6. Unicode 支持
  7. 实现细节
  8. 修订历史

Windows 2000 screenshot Windows XP - Luna - screenshot Windows XP - Aqua - screenshot

引言

使用 Windows 提供的普通属性表对用户来说很困难,尤其是当属性表包含很多页面时。在这种情况下,大多数属性表会提供多行选项卡,每次点击不在最底层的那一行的一个选项卡时,行顺序都会改变。在其他情况下,属性表可能只提供单行选项卡,您可以通过微小的箭头按钮滚动浏览。这两种解决方案对用户来说都不够方便。

这是什么?

这就是 CTreePropSheet 的用武之地:这个属性表不使用选项卡,而是提供一个树形控件,允许用户选择属性表的页面。这还允许开发人员对多个页面进行分组。一个组将显示给用户为一个带有子项(组的页面)的树项。

这种概念已经被几个产品用于设置首选项。最著名的可能是 Netscape/Mozilla 和 Visual Studio .NET。

为什么要再来一个?

已经有一些类实现了类似的对话框(例如,请参阅 SAPrefs - 类似于 Netscape 的首选项对话框)。但 CTreePropSheet 是一个特殊的实现:它不从头开始实现一个新的首选项对话框,而是基于原始的 Windows 属性表,这带来了许多优势。

  • 基于经过充分测试的代码
  • 我们免费获得了原始属性表的 所有功能
  • 通过其 HPROPSHEETPAGE 句柄添加页面,这对于提供插件机制的应用程序很有用。
  • 最重要的是:它继承自 CPropertySheet 类,并使用 CPropertyPage 对象作为页面,因此您可以使用您常用的代码,只需进行最少的更改。

特点

由于 CTreePropSheet 基于原始属性表,因此您将获得此通用对话框提供的所有功能,包括:

  • 自动调整大小以适应最大的页面
  • 支持“确定”、“取消”、“应用”和“帮助”按钮
  • 页面图标

此外,CTreePropSheet 还引入了以下功能:

  • 将页面分组到逻辑类别中
  • 根页面的默认文本
  • 根页面和子页面的默认图标
  • 一些辅助函数,使设置页面图标更容易
  • 自定义外观和风格的可能性
  • 完全支持 Windows XP 主题(在带主题和不带主题的系统上看起来都不错)

使用 CTreePropSheet

本节将不描述所有基本内容,因为您可以在 MFC 文档的 CPropertySheet 描述中找到这些内容。本节将只描述高级功能。这也是功能性的教程式描述。还提供了 完整参考

使用 CTreePropSheet 的第一步与使用 MFC 类 CPropertySheet 相同。

  1. 创建一些 CPropertyPage(或派生类)对象,并修改它们的名称以将它们分组(见下文)。
  2. 创建一个 CTreePropSheet 对象。
  3. 使用 CTreePropSheet::AddPage() 方法将 CPropertyPage 对象添加到 CTreePropSheet 对象。
  4. 使用 自定义 部分描述的方法修改属性表的样式。
  5. 调用 CTreePropSheet::DoModal() 以模态对话框形式显示属性表,或调用 CTreePropSheet::Create() 以获取非模态属性表。

如果您只想修改现有应用程序,使其使用 CTreePropSheet 类而不是 CPropertySheetClass,请按照以下步骤操作:

  1. 将所有 CPropertySheet 的出现替换为 CTreePropSheet。
  2. 更改页面的名称,以将它们分组(见下文)。

就是这样!

要将页面分组到类别中,您只需更改属性页的名称(窗口标题)。标题现在不仅应该包含页面的名称,还应该指定 CTreePropSheet 的页面树中的页面的 *路径*。字符串“::”在此处用作路径分隔符。例如,上面页面顶部的截图所示的示例应用程序有五个页面,它们被命名为:

  1. Server::Outgoing
  2. Server::Incoming
  3. Message Format::View
  4. Message Format::Composition
  5. 外观

根项“Server”和“Message Format”以及相关的页面是由 CTreePropSheet 类自动生成的,如果您不显式添加具有这些路径的页面。您可以使用 CTreePropSheet::SetEmptyPageText() 方法设置应为这些隐式根页面显示的文本。

要获取包含字符串“::”的可见名称的页面,您只需在双冒号前加上反斜杠(“\\::”)。

自定义 CTreePropSheet

本节简要概述了更改 CTreePropSheet 外观的可能性。

基础

以下方法提供了简单修改 CTreePropSheet 外观的可能性。您将在 参考 中找到每个方法的完整描述。

SetTreeViewMode()
更改以下设置(仅在创建窗口之前):
  • 在经典选项卡和树形视图模式之间切换
  • 在树形视图模式下启用/禁用页面标题
  • 在树形视图模式下启用/禁用页面树中的页面图标
SetTreeWidth()
设置树形控件的宽度。默认值为 150 像素。
SetEmptyPageText()
指定在空页面上显示的文本。空页面是为树中的根项隐式创建的页面。
SetEmptyTextFormat()
指定与 DrawText() 一起使用的标志,用于在空页面上绘制文本(主要与对齐相关的部分)。
SetTreeDefaultImages()
指定用于页面和空页面的图像,这些页面没有显式定义的图像。仅在启用了图像时才相关。
GetPageTreeControl()
在对话框创建后(即在 OnInitDialog() 中)提供对树形控件的直接访问,允许您更改树形控件的样式。
SetPageIcon() 和 DestroyPageIcon()
静态辅助函数,用于定义页面的图标并在不再需要时销毁它们。

高级

CTreePropSheet 类还提供了几种高级自定义机制,可以通过重写虚方法来实现。

页面框架和标题

从屏幕截图中可以看到,CTreePropSheet 已经支持 Windows XP 主题,这对于属性页面的背景和框架尤为重要:在非主题系统(如 Windows 2000)或禁用主题时,属性页面通常的绘制方式与属性表背景不同。这需要属性表在页面周围绘制一个框架。这个框架通常由选项卡控件提供,但由于我们不使用选项卡控件,因此在需要时必须自己绘制框架。

这个框架由 CPropPageFrame 派生类的对象绘制,该对象在 CTreePropSheet::CreatePageFrame() 中创建。此方法的默认实现会创建一个 CPropPageFrameDefault 对象,该对象会检测是否启用了主题,并使用 Windows XP 主题库(如果需要)执行相应的绘制。如果启用了页面标题(SetTreeViewMode()),该对象也负责绘制页面标题。

您可以通过重写 CTreePropSheet 的派生类中的 CreatePageFrame() 方法并创建自己的 CPropPageFrame 派生类的对象,来提供自己的框架和标题绘制机制。

页面树

通过使用 GetPageTreeControl() 方法获取指向 CTreeCtrl 的指针并修改其样式,可以对页面树进行大部分修改。如果您想注入自己的树形控件,可以在派生类中重写虚拟的 CreatePageTreeObject() 方法,并创建自己的类的对象而不是默认的 CTreeCtrl。

空页面消息

如果您想自定义由属性表生成的空页面消息,可以重写虚拟的 GenerateEmptyPageMessage() 方法。

参考

您将在源代码的头文件中找到完整的 CTreePropSheet 框架的参考。您可以使用帮助提取工具 doxygen 从源文件生成 HTML、HtmlHelp 或 LaTeX 文档(以及相应的 PDF 文档)。

要求

它应该可以在 Windows 95 或更高版本以及 Windows NT 4.0 或更高版本上运行,尽管我只在 Windows 98、Windows 2000 和 Windows XP 上进行过测试。

如果您在列出的一个或多个平台上发现问题,请告知我。

编译需要 Visual C++ 6.0 或 7.0 以及 2002 年 5 月的 Platform SDK。(如果您没有安装此 SDK,可以取消注释掉 PropPageFrameDefault.cpp 文件中 XPSUPPORT 宏(第 30 行)然后它也应该可以工作。)

Unicode 支持

虽然我没有测试过,但没有理由不支持 Unicode。

实现细节

实现方面没什么大不了的。最有趣的部分在 WM_INITDIALOG 处理程序 (OnInitDialog) 中完成。该方法会隐藏选项卡控件,水平调整属性表的大小以腾出页面树的空间,将所有现有项目移到属性表的右侧,然后在左侧创建树形控件。

其余的实现很简单。只需查看代码。如果您有任何问题,请将其发布到本文的评论部分。

修订历史

2003/02/26
  • 初始修订
2003/02/27
  • MFC7 的修复(感谢 Rainer Wollgarten)
  • 修复了在某些情况下,在 OnInitDialog() 中调整大小时窗口未正确居中的问题(感谢 Stewart Tootill)。
  • 修复了一个小拼写错误。
2003/03/03
  • [Ctrl]+[Tab] 和 [Ctrl]+[Shift]+[Tab] 快捷键现在可以按预期工作,用于在页面之间切换。一些文本更改。
© . All rights reserved.