使用 XML 的 MFC 树状态管理器






3.10/5 (9投票s)
2002年5月22日
4分钟阅读

151833

4938
在 MFC 应用程序中保存和恢复多个树状态
引言
绝大多数成功的应用程序都使用树控件向用户显示各种信息。树控件已变得如此普遍,以至于用户非常熟悉它的操作。树控件的一个常见问题是在会话之间保存状态。本文介绍了一个类 TBTreeStateMgr
,它可以轻松地保存和恢复多个树的状态。
什么是树状态?
树状态包括:
- 展开状态,哪些节点是展开的,哪些是折叠的
- 选择状态,哪些节点被选中
- 可见性状态,哪些节点当前是可见的
目前,TBTreeStateMgr
只存储展开状态。
亮点
以下是 TBTreeStateMgr
实现的亮点:
- 可以处理多个树实例
- 每个树实例必须分配一个唯一的树 ID
- 使用 XML 来存储/加载树状态
TBTreeStateMgr
中的所有方法都声明为static
。这是因为TBTreeStateMgr
的单个实例可以处理多个树状态的存储。TBTreeStateMgr
是线程安全的- 使用 COM 结构化存储来存储单个 XML 文件
使用 TBTreeStateMgr
- 在您的项目中包含以下头文件:
#include "TBTreeStateMgr.h"
- 确保在
InitInstance
函数中调用了CoInitialize
或OleInitialize
。/////////////////////// // Init COM CoInitialize(NULL);
- 将此代码放在 MFC 应用程序的
InitInstance
函数中://///////////////////////////////// // Initialize the TBTreeStateMgr // TBTreeStateMgr::Initialize();
- 将此代码放在
ExitInstance()
函数中://///////////////////////////////// // Uninitialize TBTreeStateMgr::Uninitialize();
- 要保存树状态,只需调用:
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);
- 要将树实例恢复到其保存的状态,只需调用:
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);
- [可选] 更改存储文件。
默认情况下,
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 以添加您自己喜欢的元素。例如:这可以得到增强,以保存/恢复工具栏、窗口、分隔窗格、列表、网格的状态。
许可证
本文未附加明确的许可证,但可能在文章文本或下载文件本身中包含使用条款。如有疑问,请通过下面的讨论区联系作者。
作者可能使用的许可证列表可以在此处找到。