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

使用 XML 的 MFC 树状态管理器

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.10/5 (9投票s)

2002年5月22日

4分钟阅读

viewsIcon

151833

downloadIcon

4938

在 MFC 应用程序中保存和恢复多个树状态

引言

绝大多数成功的应用程序都使用树控件向用户显示各种信息。树控件已变得如此普遍,以至于用户非常熟悉它的操作。树控件的一个常见问题是在会话之间保存状态。本文介绍了一个类 TBTreeStateMgr,它可以轻松地保存和恢复多个树的状态。

什么是树状态?

树状态包括:

  • 展开状态,哪些节点是展开的,哪些是折叠的
  • 选择状态,哪些节点被选中
  • 可见性状态,哪些节点当前是可见的

目前,TBTreeStateMgr 只存储展开状态。

亮点

以下是 TBTreeStateMgr 实现的亮点:

  • 可以处理多个树实例
  • 每个树实例必须分配一个唯一的树 ID
  • 使用 XML 来存储/加载树状态
  • TBTreeStateMgr 中的所有方法都声明为 static。这是因为 TBTreeStateMgr 的单个实例可以处理多个树状态的存储。
  • TBTreeStateMgr 是线程安全的
  • 使用 COM 结构化存储来存储单个 XML 文件

使用 TBTreeStateMgr

  1. 在您的项目中包含以下头文件:
    #include "TBTreeStateMgr.h"
  2. 确保在 InitInstance 函数中调用了 CoInitializeOleInitialize
    ///////////////////////
    // Init COM
    CoInitialize(NULL);
  3. 将此代码放在 MFC 应用程序的 InitInstance 函数中:
    ///////////////////////////////////
    // Initialize the TBTreeStateMgr //
    TBTreeStateMgr::Initialize();
  4. 将此代码放在 ExitInstance() 函数中:
    ///////////////////////////////////
    // Uninitialize
    TBTreeStateMgr::Uninitialize();
  5. 要保存树状态,只需调用:  
    BOOL TBTreeStateMgr::SaveTreeState(LPCTSTR lpszTreeContextName,CTreeCtrl * pTreeCtrl);
    注意:此函数通常在窗口关闭之前调用。例如:通过处理 WM_CLOSE 消息。
    //This call saves the specified tree instance. "My Tree1 View" is the name of the instance.
    TBTreeStateMgr::SaveTreeState(_T("My Tree1 View"),&wnd_TreeCtrl);
  6. 要将树实例恢复到其保存的状态,只需调用:
    BOOL TBTreeStateMgr::LoadTreeState(LPCTSTR lpszTreeContextName,CTreeCtrl * pTreeCtrl);

    注意:此函数通常在树控件初始化数据后立即调用。例如:在 OnInitialUpdate() 函数中。

    //This call restores the wnd_TreeCtrl to a state stored under the name <code>"My Tree1 View"
    TBTreeStateMgr::LoadTreeState(_T("My Tree1 View"),&wnd_TreeCtrl);
  7. [可选] 更改存储文件。

    默认情况下,TBTreeStateMgr 将结构化存储文件存储在当前目录下的 "CTLStateStg.ctss" 文件名中。如果您想指定不同的目录或路径,请使用 SetStorageFile(LPCTSTR lpszNewFile)

    // Change the storage file location
    TBTreeStateMgr::SetStorageFile(_T("e:\\MyDir\\ILikeThisDir\\MyStorageFile.strg"));

要重置所有树状态,只需删除 "CtlStateStg.ctss" 文件。如果找不到该文件,它将自动生成。

实现

本节简要介绍了我在项目中必须做出的一些实现选择。我希望我对 XML 和 IStorage/IStream 的使用能够展示这些工具的强大功能。结构化存储实际上被 MS Word 使用。DOC 格式实际上是 IStorage 兼容文件。

传统方法

有许多机制可以存储和检索树状态。一种流行的方法似乎是将树状态存储在注册表中。对于使用树控件的文档/视图应用程序,一些开发人员选择将最新的树状态作为文档的一部分进行存储。这样,每个文档都可以恢复到上次关闭时的视图状态。注册表方法不安全、不可靠且不具扩展性。大多数项目没有奢侈的条件去修改文档文件以适应存储最新状态。无论如何,将视图状态与文档对象一起存储是一个坏主意。

引入 XML

在评估存储树控件状态的技术时,我偶然发现了 XML。XML 本身也是高度树状结构的。如果我们能以高效的方式将树状态传输到 XML 文档中,并再将其传回,我们将拥有一个非常出色的解决方案。MSXML 解析器非常高效,并且随着 IE5 的广泛部署而可用。TBTreeStateMgr 中的大部分代码都用于将树状态转换为 XML 再转换回来。此项目的 XML DTD 为:

<!-- TBTreeStateMgr.dtd   --	The DTD for storing tree state -->
<!ELEMENT TreeState(ExpandedNodes)>
	<!ELEMENT ExpandedNodes(node*)>
	    <!ELEMENT node (#PCDATA)>
<!-- . . end . . -->

IStorage/IStream

下一个主要问题是:如何存储多个树?

如果您使用 "Docfile Viewer" 打开 CtlState.ctss,我们可以看到以下结构:

如上图所示,DOCfile 将每个 XML 文档存储在一个单独的流中。这种架构的原因是:任何大型应用程序都必须处理多个树(或)同一树的多个用户视图。应用程序还可能在多个文档的视图中有树。例如:每个书籍文档都可以有一个树视图显示目录。如果我们为每个树实例创建一个不同的 XML 文档,我们最终可能会有数百个文件。另一个令人安心的因素是结构化存储被 Microsoft 广泛用于其自身的产品中(MS Word/Excel 将 DOC、XLS 文件存储在结构化存储中)。

增强功能

这可以得到增强,以支持任何状态的存储。只需更改 XML DTD 以添加您自己喜欢的元素。例如:这可以得到增强,以保存/恢复工具栏、窗口、分隔窗格、列表、网格的状态。

许可证

本文未附加明确的许可证,但可能在文章文本或下载文件本身中包含使用条款。如有疑问,请通过下面的讨论区联系作者。

作者可能使用的许可证列表可以在此处找到。

© . All rights reserved.