Delphi Firemonkey-无法将TTabItem的子子类添加到TTabControl

时间:2019-02-05 15:32:06

标签: delphi

我可以将TTabItem添加到TTabControl,可以将TTabItem的子类添加到TabControl,但是不能将TTabItem的子类添加到TabControl。

Firemonkey应用程序示例-具有TTabControl的表单:

type
   TTabItem_subclass = class (TTabItem);
   TTabItem_sub_subclass = class (TTabItem_subclass);

procedure TForm1.FormCreate(Sender: TObject);
 procedure add_tab (t: TTabItem);
   begin
     t.Text := t.ClassName;
     t.Parent := TabControl1
  end;
begin
  add_tab (TTabItem.create (TabControl1));   // <-- works
  add_tab (TTabItem_subclass.create (TabControl1));  // <-- works
  add_tab (TTabItem_sub_subclass.create (TabControl1));  // <-- fails
end;

运行该应用程序时,TTabItem_sub_subclass不显示:

enter image description here

我在XE5和东京都尝试过,结果相同。我想念什么?

1 个答案:

答案 0 :(得分:0)

简短的回答:我认为您没有丢失任何东西。实际上,您的代码确实成功地将子类别的项目添加到TabControl中,只是没有显示出来。我认为此问题是由FMX代码派生用于绘制类的样式的方式引起的,该类是TTabItem的子子类。我对FMX的了解不足,无法确定问题的确切原因,但我已经确定了似乎可以解决此问题的方法。

请参阅下面的示例项目代码,该代码成功显示了两者 TabItem子类和TabItem子_子类选项卡。

按原样构建代码的原因是,可以轻松地在其上设置更改的内存断点 TabItem的FResourceLink字段(代码中的变量Item),而我当时 试图追踪绘画过程的发生方式。

通过查看TabItem.Paint方法,很明显该选项卡只会绘制 如果其FResourceLink不为零。您原始代码(和我的代码)的问题 是当在TabItem_subClass上调用Paint时,其FResourceLink 已分配 一个值,而对于TabItem_sub_subClass,它。显然,FResourceLink 在此处获取用于绘制TabItem的样式的名称,如果 无法找到TabItem不会被绘制。

恐怕由于我不是FMX专家,我发现它的代码有些迷宫 在最佳时机,样式的实现更是如此。但它 令我震惊的是,如果我可以确保返回有效的样式名称, TabItem GetParentClassStyleLookupName方法,就足够了。那就是原因 TCustomItem_sub_subclass.GetParentClassStyleLookupName覆盖。我想 FMX专家可能会认为它像是一把大锤,可以裂开核桃,但是在那里 你去。

代码

  type
    TForm1 = class(TForm)
      TabControl1: TTabControl;
      StyleObject1: TStyleObject;  // ignore this
      procedure FormCreate(Sender: TObject);
    private
    public
       Item :  TTabItem;
    end;

  [...]

  implementation

  [...]

  type
     TCustomItem_subclass = class (TTabItem)
     public
       constructor Create(AOwner : TComponent); override;
     end;

     TCustomItem_sub_subclass = class (TCustomItem_subclass)
       public
       constructor Create(AOwner : TComponent); override;
       function GetParentClassStyleLookupName: string; override;
     end;

  procedure TForm1.FormCreate(Sender: TObject);

   procedure add_tab (t: TTabItem);
     begin
       t.Text := t.ClassName;
       t.Parent := TabControl1
    end;

   begin

  {$define UseSubSub}
  {$ifdef UseSubSub}
     Item := TCustomItem_sub_subclass.Create(TabControl1);
  {$else}
     Item := TCustomItem_subclass.Create(TabControl1);
  {$endif}

     Item.Text := Item.ClassName;
     Item.Parent := TabControl1;

     Caption := TabControl1.ActiveTab.Text;

     Item := TCustomItem_subclass.Create(TabControl1);

     Item.Text := Item.ClassName;
     Item.Parent := TabControl1;

  end;

  constructor TCustomItem_subclass.Create(AOwner: TComponent);
  begin
    inherited;
  end;

  constructor TCustomItem_sub_subclass.Create(AOwner: TComponent);
  begin
    inherited;
  end;

  function TCustomItem_sub_subclass.GetParentClassStyleLookupName: string;
  begin
    Result := 'tabitemstyle';
  end;

顺便说一句,在执行此操作时,我注意到该函数中似乎存在一个潜在的错误 FMX.Controls.Pas中的TStyledControl.GenerateStyleName(const AClassName: string): string 如果从前导AClassName中删除的TCustom参数以双TT开头, 与TCustomTabItem中一样,该代码错误地删除了TabItem的T。我没有 时间或精力去进一步探索,但这就是为什么我的TabItem子类忽略的原因 Tab的名字。