【发布时间】:2013-09-02 18:05:19
【问题描述】:
注意
抱歉,这篇文章很长,我认为最好尽可能多地提供信息,而不是在需要时填补空白。
请注意,尽管我也将其标记为 Delphi 并且拥有并仍在使用 Delphi XE 我现在使用 Lazarus 作为我的主要 IDE,但我根本买不起较新的 Delphi 版本,现在 Lazarus 变得更加稳定我觉得改用 Lazarus。
对于这个问题,我在项目源代码中包含了一个 zip 附件,虽然它是用 Lazarus 编写的,但它确实有助于解决我的问题,因此第一段中的 cmets。
概述
关于这个问题,我有一个对象,它拥有多个作为 TLists 的类。
我在 Treeview 中表示这些数据,并且无法知道树中将存在多少级别和节点,因为它们是在运行时动态创建的。我设置的一个限制是顶级节点将被固定,这意味着它们不能被删除或重命名 - 我将这些称为 RootGroups。
Treeview 将填充项目和组,添加到 Treeview 的每个节点都将有自己的对象分配给数据以正确识别每个项目。我现在将展示一个示例屏幕截图,以便在继续之前给出一个更好的主意:
如您所见,我有两个最顶端的节点,Object1Root 和 Object2Root。如果您注意到右侧的按钮,它们允许将组和项目添加到 Treeview,但如果它们不属于 Treeview 的该部分,它们将被禁用。例如,您不能在 Object1Root 下添加 Object2Group 或 Object2Item。
基本上,树视图中的所有内容都有自己的指向对象的指针。我从基础对象派生的每个对象。此基础对象具有存储它在 Treeview 中的位置的属性,如下所示:
type
TBaseObject = class
private
FName: string;
FGroup: string;
FNodeLevel: Integer;
FNodeIndex: Integer;
public
constructor Create(AName: string);
destructor Destroy; override;
published
property Name: string read FName write FName;
property Group: string read FGroup write FGroup;
property NodeLevel: Integer read FNodeLevel write FNodeLevel;
property NodeIndex: Integer read FNodeIndex write FNodeIndex;
end;
然后我可以从基础对象派生我的其他类,如下所示:
type
TObject1RootGroup = class(TBaseObject)
public
constructor Create(AName: string);
destructor Destroy; override;
procedure ToSave(const XMLDoc: IXMLDocument; var Root, Node: IXMLNode);
end;
TObject1Group = class(TBaseObject)
public
constructor Create(AName: string);
destructor Destroy; override;
procedure ToSave(const XMLDoc: IXMLDocument; var Root, Node: IXMLNode);
end;
TObject1Item = class(TBaseObject)
private
FSomeVal1: string;
FSomeVal2: string;
public
constructor Create(AName: string);
destructor Destroy; override;
procedure ToSave(const XMLDoc: IXMLDocument; var Root, Node: IXMLNode);
published
property SomeVal1: string read FSomeVal1 write FSomeVal1;
property SomeVal2: string read FSomeVal2 write FSomeVal2;
end;
包含所有这些类的主对象如下所示:
type
TMyObject = class(TObject)
private
FName: string;
FObject1Groups: TList;
FObject1Items: TList;
FObject2Groups: TList;
FObject2Items: TList;
protected
procedure FreeObjects;
public
constructor Create(AName: string);
destructor Destroy; override;
procedure Save(FileName: string);
function Load(Filename: string): Boolean;
published
property Name: string read FName write FName;
property Object1Groups: TList read FObject1Groups;
property Object1Items: TList read FObject1Items;
property Object2Groups: TList read FObject2Groups;
property Object2Items: TList read FObject2Items;
end;
当我将 Main Object 保存到 XML 时,我首先迭代整个 TreeView,然后为每个对象分配节点数据,例如父级、级别、索引等。输出 XML 文件基于第一个图像看起来像这样:
注意:SomeVal 部分并不重要,因为我从不费心向对象写入任何内容。
我真正应该做的就是保存到 XML,就像树视图一样。我对 XML 不太熟悉,因为我仍在掌握它,但我认为输出应该是这样的:(用记事本编写)
<XML Name="test.xml">
<Counts Object1Groups="3" Object1Items="5" Object2Groups="2" Object2Items="1" />
<TObject1RootGroup Name="Object1Root" Group="" NodeLevel="0" NodeIndex="0"
<TObject1Item Name="Item1" Group="Object1Root" NodeLevel="1" NodeIndex="0" SomeVal1="" SomeVal2="" />
<TObject1Item Name="Item2" Group="Object1Root" NodeLevel="1" NodeIndex="1" SomeVal1="" SomeVal2="" />
<TObject1Group Name="Group1" Group="Object1Root" NodeLevel="1" NodeIndex="2" />
<TObject1Item Name="Item3" Group="Object1Root" NodeLevel="1" NodeIndex="3" SomeVal1="" SomeVal2="" />
<TObject1Group Name="Group2" Group="Object1Root" NodeLevel="1" NodeIndex="4" />
<TObject1Item Name="Item1" Group="Group2" NodeLevel="2" NodeIndex="0" SomeVal1="" SomeVal2="" />
<TObject1Group Name="Group1" Group="Group2" NodeLevel="2" NodeIndex="1" />
<TObject1Item Name="Item1" Group="Group1" NodeLevel="3" NodeIndex="0" SomeVal1="" SomeVal2="" />
<TObject2RootGroup Name="Object2Root" Group="" NodeLevel="0" NodeIndex="1"
<TObject2Group Name="Group1" Group="Object2Root" NodeLevel="1" NodeIndex="0" />
<TObject2Group Name="Group2" Group="Object2Root" NodeLevel="1" NodeIndex="1" />
<TObject2Item Name="Item1" Group="Group2" NodeLevel="2" NodeIndex="0" SomeVal1="" SomeVal2="" />
</XML>
然后我可以从 XML 加载 TreeView。问题是我现在只知道如何保存 XML,我知道需要某种递归等,这就是我要努力的地方,尤其是从 XML 文件重建树。
附件
我花了几个小时将我的实际项目代码精简为一个更易于阅读和理解的示例,它是用 Lazarus 编写并使用 OmniXML 库,我只包含了源单元没有项目文件。
在这里下载(密码是stackoverflow):http://www34.zippyshare.com/v/16401041/file.html
最后我的问题是:
- 如何以正确的层次结构保存到 XML。
- 如何加载 XML 并将 Treeview 重建为保存前的样子。
非常感谢。
【问题讨论】:
-
你已经问了两次了。也许删除另一个 Q。
-
@DavidHeffernan 抱歉,这是一个真正的错误,我忘了删除它。在花了很长时间编写问题并整理示例之后,我需要喝一杯。
-
好的,我明白了。这是一个更好的 Q,+1。
-
您是否保存在 xml 中,以便您可以出于其他原因使用该文件?只是您可以使用 TTreeView 的 Read 和 Write 组件方法来执行此操作。如果这太过分了,那么代码值得一看。
-
@TonyHopkinson 我认为我这样做的方式更好,因为它本质上是以更清洁的方式序列化我的对象。我曾经使用 WriteComponentRes,发现它很脏,现在我使用 Lazarus 保存到 XML 对它的可读性和可移植性来说是有意义的,尤其是在我交叉编译时。对于它在我的真实代码中的价值,我确实存储了比我基础编码的基本类型、流数据等更多的东西。
标签: xml delphi delphi-xe lazarus