5

I want to add a TList with a TTreeViewItem and a custom class (TRoom)'s object with another. In delphi 2007 there was a field 'Data' of Pointer type which has been replaced with a TValue here which I don't know as to how to use. I have searched the internet with some stating that it can't handle custom types for the time being.

Can somebody devise a way to achieve this, except for making a hack class?

For example, the following form code should run properly:-

unit Unit1;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Rtti, System.Classes,
  System.Variants, FMX.Types, FMX.Controls, FMX.Forms, FMX.Dialogs,
  FMX.TreeView, FMX.Layouts, FMX.Edit;

type
  TRoom = class

    ID : WORD;
    Name : String;

  end;

  TForm1 = class(TForm)
    TreeView1: TTreeView;
    TreeViewItem1: TTreeViewItem;
    Button1: TButton;
    Edit1: TEdit;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  end;

var
  Form1: TForm1;

implementation

{$R *.fmx}

procedure TForm1.Button1Click(Sender: TObject);
var
  List : TList;
begin

  // Get The List From TreeViewItem1
  // pani's Solution  - List := TList ( TreeViewItem1.TagObject );

  Edit1.Text := TRoom ( List.First ).Name;

end;

procedure TForm1.FormCreate(Sender: TObject);
var
  Room : TRoom;
  List : TList;

begin

  List := TList.Create;
  Room := TRoom.Create;
  Room.ID := 5;
  Room.Name := IntToStr ( 5 );
  List.Add ( Room );

  // Add The List To TreeViewItem1    
  // pani's Solution  - TreeViewItem1.TagObject := List;

end;

end.
4

2 回答 2

3

If you want to "attach" an object to TControl, TControl's parent class TFmxObject introduces the .TagObject property that stores any object value.

Besides using this property you can also use the .Tag property with typecasting into NativeInt and your wanted class type, for example: TreeViewItem1.Tag := NativeInt(List); and List := TList(TreeViewItem1.Tag);

于 2013-11-24T13:58:04.897 回答
1

在“小“g”的通用方式中,DataFMX 控件的属性应该获取或设置控件的核心值。在某种TImage情况下,这将是显示的位图,对于TEdit文本等。因此,它的目的与DataVCL 树视图项的属性完全不同,后者是将任意数据从对象中挂起。

正如 pani 正确回答的那样,如果您想挂起对 FMX 树视图项的任意对象引用,那么您可以使用TagObject. 也就是说,尽管对 FMX 对正确 OOP 行为的影响(参见此处)感到恼火,但如果您正在动态创建树视图项,那么更好的方法可能是派生自定义TTreeViewItem后代:

uses System.Generics.Collections;

type
  TRoomTreeViewItem = class(TTreeViewItem)
    RoomList: TList<TRoom>; //better use a generic than non-generic list as mentioned above
  end;

或者,如果房间列表的生命周期与其关联的树视图项的生命周期相同,您实际上可以将列表封装在项目中:

type
  TRoomTreeViewItem = class(TTreeViewItem)
  strict private
    FRoomList: TObjectList<TRoom>;
    function GetRoom(Index: Integer): TRoom;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    function GetEnumerator: TEnumerator<TRoom>;
    function AddRoom: TRoom;
    property Rooms[Index: Integer] read GetRoom;
  end;

constructor TRoomTreeViewItem.Create(AOwner: TComponent);
begin
  inherited;
  FRoomList := TObjectList<TRoom>.Create;
end;

destructor TRoomTreeViewItem.Destroy;
begin
  FRoomList.Free;
  inherited;
end;

function TRoomTreeViewItem.GetEnumerator: TEnumerator<TRoom>;
begin
  Result := FRoomList.GetEnumerator;
end;

function TRoomTreeViewItem.GetRoom(Index: Integer): TRoom;
begin
  Result := FRoomList[Index];
end;

function TRoomTreeViewItem.AddRoom: TRoom;
begin
  Result := TRoom.Create;
  FRoomList.Add(Result);
end;

有些人可能会认为第二个变体是非 UI 与 UI 代码的可怕混合——尽管 YMMV,我个人并不反对它(事实上,这就是我建议它的原因)。

于 2013-11-24T16:48:24.067 回答