【问题标题】:Advice on setting up new TreeView Data Type关于设置新 TreeView 数据类型的建议
【发布时间】:2011-09-18 18:51:11
【问题描述】:

我想要一些关于如何使用 TreeView 的 Node.Data 属性为 TreeView 设置新对象类的建议和/或提示。

我知道如何创建一个可以从 .Data 属性写入/读取的基本 Object 类型,我会这样做:

type
  TMyData = class(TComponent)
  private
    FString1: String;
    FString2: String;
    FInteger1: Integer;
  published
    property String1: String read FString1 write FString1;
    property String2: String read FString2 write FString2;
    property Integer1: Integer read FInteger1 write FInteger1;
  end;

将值写入 Node.Data 属性之一:

TMyData(TreeView1.Selected.Data).String1:= 'save this String';

读取值:

ShowMessage(TMyData(TreeView1.Selected.Data).String1);

这是将数据分配给树节点的一个非常基本的示例,现在这是我需要帮助和建议、提示等的地方...

从我上面的示例中,您可以轻松地读取/写入标准属性,例如字符串、整数、布尔值等。包含和读取/写入 TListBox 或 TListView 怎么样?

与其将标准数据写入树节点,不如将项目添加到该 TListView 并将该 TListView 的内容写入 TreeView 节点。

如果单击其中一个树节点时,它不会返回字符串,而是使用之前保存的项目和图像填充该 TListView。

(1) 这是您可以将节点添加到 TreeView 的主要形式。我实际上使用了一个更增强的功能来添加到我的 TreeView 中,如下所示:

function AddMyDataNode(ATreeView: TTreeView; NodeName: String; NodeImage: Integer;
    String1, String2: String; Integer1: Integer;
    SelectNode: Boolean): TTreeNode;
var
  Obj: TMyData;
  Node: TTreeNode;
begin
  Result:= nil;

  Obj:= TMyData.Create(nil);
  try
    Obj.String1:= String1;
    Obj.String2:= String2;
    Obj.Integer1:= Integer1;

    Node:= ATreeView.Items.AddObject(ATreeView.Selected, NodeName, Obj);
    Node.ImageIndex:= NodeImage;
    Node.SelectedIndex:= NodeImage;

    Result:= Node;

    if SelectNode then
      Node.Selected:= True;

    ATreeView.SetFocus;
  except on E: Exception do
    ShowMessage('Could not add MyData Node: ' + E.Message);
  end;
end;

编辑节点将显示另一个称为数据表单的表单...:

(2) 此数据表单是读取/写入来自主表单上的节点的数据的位置。添加了一个 TListView。 ListView 也应该使用标准属性读取/保存。

添加/编辑 ListView 项可能包括其他标准属性,例如:

(3) 此表单上的值保存到 ListView 数据中。

简而言之:

  • TreeView Node.Data 存储 标准属性,也是一个 TListView。
  • 此数据以另一种形式显示 称为数据表单。
  • 数据表单上的 ListView 也 有数据。
  • 在数据表单上编辑 ListView 将显示一个额外的表格 标准属性。

我想知道如何最好地解决这个问题,您可以提供哪些提示,实现此类目标的最简单方法是什么?

ListView 的写入/读取很容易实现,我想这可以通过访问ListView Items.Item[x].Data 属性来完成。让 ListView 数据与 TreeView 一起存储是问题所在,我不知道如何实现这种行为。

我想了解有关如何定义类型等方面的建议。

我期待听到您对此的想法。

【问题讨论】:

  • 您当前将对象引用放入Data 属性的方法可以很好地扩展。您只需要继续添加到TMyData。另一种选择是继承TTreeNode 并使用TTreeView.OnCreateNodeClass
  • 我只是对如何设置/获取 ListView 数据以与 TreeView 数据协调工作感到困惑。编辑每个树节点以显示数据表单将始终具有不同的 ListView 项。标准属性好办,ListView比较难。
  • 为什么列表视图更难?我不明白。
  • 不应该,我编辑了我的问题以更清楚地说明这个问题,也许问题没有被正确理解。因为 ListView 也会使用数据,例如 Items.Item[x].Data,所以这个 ListView 数据也必须读/写到 TreeView 的 Node.Data 属性中。我一定是在迷惑自己或其他什么,因为我没有找到简单的答案。
  • 我不知道你为什么不只是在TMyData 中添加一个列表视图字段,但我必须承认你的问题太长了,我每次尝试从上到下阅读它时都会呆滞底部!也许别人比我更有耐力!

标签: delphi listview treeview


【解决方案1】:

我认为您的困惑是考虑存储 Visual Forms 和组件,包括它们的数据。我相信你可以用流媒体系统做到这一点——虽然我从来没有!我喜欢将数据和视觉效果尽可能分开。

因此,您需要一个自定义列表来放入 MyData,其中包含需要进入列表视图的所有数据和设置,例如 MyDataList:(我正在直接输入!)

type

TMyDataViewData = class(TPersistent)
  Caption: string;
  ImageIndex: Integer;
  StateIndex: Integer;
  Group: Integer;
  MemoData: TStrings;
end;

TMyDataViewDataList = class(TPersistent)
  TheList: TObjectList;
  property Items[Index:Integer]:MyDataViewData read getItems write SetItems;
  property Count: Integer read GetCount;
  . 
  .
  .
end;

  TMyData = class(TComponent)
  private
    FString1: String;
    FString2: String;
    FInteger1: Integer;
  private 
    MyForm: TMyEditform;
  published
    procedure Edit(Owner: TComponent);
    property String1: String read FString1 write FString1;
    property String2: String read FString2 write FString2;
    property Integer1: Integer read FInteger1 write FInteger1;
    property TheDataList: TMyDataViewDataList read fTheDataList write fTheDataList;  
end;

procedure TMyData.Edit;
var
  F: TMyEditForm;
begin
  F:= TMyEditForm.create(Owner);
  F.DataList := TheDatalist;  // data for listview and memos
  F.ShowModal;
  .
  .
  . 
end;

然后在你的 Treeview 中你只需要做:

  If TreeNode.Data is TMyData then
    TMyData(TreeNode.Data).Edit(Self);

编辑后用于更改树视图节点信息的所有数据都应该在 MyData 所以你可以做

  Node.Text := TMyData(Node.Data).TheDataList.Items[0].Caption;

for i := 0 to TMyData(Node.data).TheDataList.Count do
    Node.AddChild(TMyData(Node.Data).TheDataList.Items[i].Caption);

您还可以轻松地将 Datalist 的属性直接公开给 TMyData :)

之类的。那里可能有一些语法错误!

【讨论】:

  • 感谢您的发帖,我认为您是对的,因为我正在考虑将实际的 Listview 存储在其中(因为项目图像、标题等)。我会试试这个谢谢..
  • 您写道,您希望将 gui 与数据尽可能分开——这是一个很好的做法。但在您的代码中,您会做相反的事情:数据类包含一个表单。 '编辑表格。执行(myData)'会更好恕我直言。
  • @craig:请注意,如果您有 d2009 或更高版本,则不需要包装 TObjectList 的自定义列表类。只需使用通用的 TObjectList.
  • @Smasher 我正在使用 XE,仍在学习泛型,我知道它在 Generics.Collections 中,但仅此而已:)
  • @smasher - 触摸! - 正如我所说,我是直接输入的(并尽可能简单)。你是对的。
【解决方案2】:

我认为您的方法没有任何问题。你可以让你的数据对象包含一个对象列表(我不知道你为什么从TComponent继承一个与可视组件无关的类):

TMyData = class
private
  FString  : String;
  FInteger : Integer;
  FItems   : TList <TItem>   // where TItem is your custom object class
public
  // ... properties ...
end;

此列表随后显示在列表框中:

 for Item in MyData.Items do
   ListBox.Items.AddObject (Item.ToString, Item);

如果您编辑其中一个项目,您会做同样的事情:从列表框的数据中取出对象并将其传递给下一个表单。

希望对您有所帮助。

【讨论】:

  • 我从 TComponent 派生出来,因为我想如果它涉及 ListView,我会需要它。感谢您的提示和代码示例,我会看看我是否可以实现这个......
  • 你的数据类中不应该有TListView(如果你愿意,你不需要从TComponent派生)。列表视图属于 GUI,应使用 TList 之类的内容填充。
  • 在您的指导下,我意识到这一点 :) 我仍然在初级水平上学习 Delphi 和 OOP。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-01
  • 1970-01-01
  • 2018-11-02
  • 1970-01-01
  • 1970-01-01
  • 2011-01-03
相关资源
最近更新 更多