1

使用德尔福 10.4。我希望有人能解释我的 FMX 做错了什么TTreeView,导致EArgumentOutOfRangeException. 我正在尝试创建一个自定义TTreeViewItem类,该类允许我将一些数据与每个节点相关联,并提供一个就地编辑器来允许更改节点文本。

下面的代码是我正在做的精简版本。FMX 表单上有一个TTreeview和两个按钮,表单Onshow设置为FormShow,按钮设置为两个按钮事件。

TVLinkTreeViewItem是我的自定义TTreeViewItem,我在其中为我的就地编辑器添加背景和编辑组件,双击节点时会显示该组件。

当您按原样运行代码时,当逻辑到达例程TreeView1.EndUpdate末尾的调用时,程序将抛出FormShow异​​常。FMX.Controls在过程中抛出异常TControl.EndUpdate

如果您注释掉ExpandAll调用,则不会抛出异常,但如果您弄乱了节点的展开和折叠以及表单的大小调整,迟早会抛出异常。我在下面的代码中留下了这一ExpandAll行,因为我认为异常是由相同的错误引起的。

据我所知,问题似乎是我如何设置fBackgroundand fEditor。如果我不调用AddObject例程并且不设置Parent属性,我也不会例外。

那么谁能告诉我我做错了什么?TTreeViewItems或者有没有更好的方法来为 FMX组件进行就地编辑?

unit Unit1;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.TreeView, FMX.Layouts, FMX.Controls.Presentation,
  FMX.MultiView, FMX.Edit, FMX.Objects, FMX.StdCtrls;

type
  TForm1 = class(TForm)
    TreeView1: TTreeView;
    Button1: TButton;
    Button2: TButton;
    procedure FormShow(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.fmx}

type
  TVLinkTreeViewItem = class(TTreeViewItem)
  private
    fData: string;
    fEditor: TEdit;
    fBackground: TRectangle;
    procedure TreeViewItem1DblClick(Sender: TObject);
    procedure EditorExit(Sender: TObject);
    procedure EditorKeyUp(Sender: TObject; var Key: Word; var KeyChar: Char; Shift: TShiftState);
  public
    property Editor: TEdit read fEditor write fEditor;
    property Data: string read fData write fData;
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  TreeView1.ExpandAll;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  TreeView1.CollapseAll;
end;

procedure TForm1.FormShow(Sender: TObject);
var
  I, c, r, s: Integer;
  vNode1,
  vNode2,
  vNode3,
  vNode4: TVLinkTreeViewItem;
begin
  TreeView1.BeginUpdate;
  TreeView1.Clear;
  for I := 0 to 4 do
    begin
      vNode1 := TVLinkTreeViewItem.Create(TreeView1);
      vNode1.Text := 'Level 1 - '+ IntToStr(I);
      TreeView1.AddObject(vNode1);
      for c := 0 to 4 do
        begin
          vNode2 := TVLinkTreeViewItem.Create(vNode1);
          vNode2.Text := 'Level 2 - '+ IntToStr(c);
          vNode1.AddObject(vNode2);
          for r := 0 to 4 do
            begin
              vNode3 := TVLinkTreeViewItem.Create(vNode2);
              vNode3.Text := 'Level 3 - '+ IntToStr(r);
              vNode2.AddObject(vNode3);
//              for s := 0 to 4 do
//                begin
//                  vNode4 := TVLinkTreeViewItem.Create(vNode3);
//                  vNode4.Text := 'Level 4 - '+ IntToStr(s);
//                  vNode3.AddObject(vNode4);
//                end;
            end;
        end;
    end;
  //ExpandAll works when no parent is set for fBackGround and fEditor is not set in "TVLinkTreeViewItem.Create" below"
  //If the Parents are set below, ExpandAll/EndUpdate causes "Augument out of range" exception.
  TreeView1.ExpandAll;
  treeView1.EndUpdate;
end;

{ TVLinkTreeViewItem }

constructor TVLinkTreeViewItem.Create(AOwner: TComponent);
begin
  inherited;
  fData := '';
  fBackground := TRectangle.Create(AOwner);
  //When ExpandAll is not called in FormShow,
  //   Calling "AddObject" or setting parent, as shown below, make all the code work,
  //   but will get intermident "Augument out of range" exceptions when resizing form,
  //   or when expanding or collapsing nodes using the buttons.
  self.AddObject(fBackGround);
  //fBackGround.Parent := self;
  fBackGround.Visible := false;
  fEditor := TEdit.Create(AOwner);
  fBackGround.AddObject(fEditor);
  //fEditor.Parent := fBackGround;
  fEditor.Visible := false;
  fEditor.Align := TAlignLayout.Client;
  fEditor.OnKeyDown := EditorKeyUp;
  self.OnDblClick := TreeViewItem1DblClick;
  fEditor.OnExit := EditorExit;
end;

destructor TVLinkTreeViewItem.Destroy;
begin

  inherited;
end;

procedure TVLinkTreeViewItem.TreeViewItem1DblClick(Sender: TObject);
begin
  fBackGround.Visible := true;
  fBackGround.Width := self.Width - 20;
  fBackGround.Height := self.Height;
  fBackGround.Position.X := 20;
  fEditor.Enabled := true;
  fEditor.Visible := true;
  fEditor.Opacity := 1;
  fBackGround.BringToFront;
  fEditor.BringToFront;
  fEditor.Text := Text;
  fEditor.SetFocus;
  fEditor.SelectAll;
end;

procedure TVLinkTreeViewItem.EditorKeyUp(Sender: TObject; var Key: Word; var KeyChar: Char; Shift: TShiftState);
begin
  inherited;
  if Key = vkReturn then
    begin
      Text := fEditor.Text;
      fBackGround.Visible := false;
      fEditor.Enabled := false;
    end
  else if Key in [vkEscape, vkCancel, vkTab, vkHardwareBack] then
    begin
      fBackGround.Visible := false;
      fEditor.Enabled := false;
    end;
end;

procedure TVLinkTreeViewItem.EditorExit(Sender: TObject);
begin
  fBackGround.Visible := false;
  fEditor.Enabled := false;
  fEditor.Visible := false;
end;

end.

这是 fmx 的内容:

object Form1: TForm1
  Left = 0
  Top = 0
  Caption = 'Form1'
  ClientHeight = 480
  ClientWidth = 640
  FormFactor.Width = 320
  FormFactor.Height = 480
  FormFactor.Devices = [Desktop]
  OnShow = FormShow
  DesignerMasterStyle = 0
  object TreeView1: TTreeView
    Align = Left
    Size.Width = 269.000000000000000000
    Size.Height = 480.000000000000000000
    Size.PlatformDefault = False
    TabOrder = 0
    Viewport.Width = 265.000000000000000000
    Viewport.Height = 476.000000000000000000
  end
  object Button1: TButton
    Position.X = 356.000000000000000000
    Position.Y = 68.000000000000000000
    TabOrder = 2
    Text = 'Expand'
    OnClick = Button1Click
  end
  object Button2: TButton
    Position.X = 354.000000000000000000
    Position.Y = 102.000000000000000000
    TabOrder = 1
    Text = 'Collapse'
    OnClick = Button2Click
  end
end
4

0 回答 0