代码之家  ›  专栏  ›  技术社区  ›  maf-soft

如何将TTabControl的每个选项卡置于其自己的单元中/使用TFrame而不是选项卡?

  •  1
  • maf-soft  · 技术社区  · 8 年前

    我有一个FMX应用程序(但在VCL中应该是相同的),其中有一个TabControl显示10个选项卡。选项卡设置为可见或不可见,具体取决于应用程序状态和用户权限。

    它工作得很好,但我不喜欢

    • 一切都在一起,在主要形式上混乱不堪

    • 和选项卡内容被初始化,即使它们从未可见。

    所以我考虑使用在选项卡可见时创建的框架。

    每个帧只能存在一次,并且应该可以很容易地从一个帧操纵另一个帧(另一个帧上的访问控制)。

    我喜欢优雅的解决方案和简短的代码:)

    这是我已经找到的,很好,但很旧: Replacing TabSheets with Frames - by Dan Miser

    1 回复  |  直到 8 年前
        1
  •  0
  •   maf-soft    8 年前

    此解决方案的每个帧都有一个全局变量。所有框架都可以 使用 主窗体单元位于其实现部分,可以轻松访问其他框架及其所有控件,即使不向uses子句添加其他框架也是如此。

    选项卡开始时不可见,其框架未初始化。 TabA.Activate; 显示选项卡并设置焦点。 TabA.Frame.Label1 轻松访问该框架上的控件。 TabA.Visible:= False; 隐藏选项卡并释放框架。

    泛型在这里非常有用,我喜欢。

    非常欢迎提出改进意见。。。

    type
      TFormMain = class(TForm)
        TabControl: TTabControl;
        TabInfo: TTabItem;
        procedure FormCreate(Sender: TObject);
      private
        procedure AddTab<T: TTabItem>(out Tab: T);
      public
        TabA: TTabItemFrame<TFrameA>;
        TabB: TTabItemFrame<TFrameB>;
        TabC: TTabItemFrame<TFrameC>;
      end;
    
    var
      FormMain: TFormMain;
    
    implementation
    
    procedure TFormMain.FormCreate(Sender: TObject);
    begin
      AddTab(TabA);
      AddTab(TabB);
      AddTab(TabC);
    
      TabA.Activate;
    end;
    
    procedure TFormMain.AddTab<T>(out Tab: T);
    begin
      Tab:= TabControl.Add(T) as T;
    end;
    
    ---------------------------------------------------------------------
    unit _FrameBase;
    
    interface
    
    uses
      System.Classes, FMX.Forms, FMX.TabControl;
    
    type
      TFrameBase = class abstract(TFrame)
      public
        class function GetTitle: string; virtual; abstract;
      end;
    
      TTabItemFrame<T: TFrameBase> = class(TTabItem)
      private
        FFrame: T;
      protected
        procedure Hide; override;
        procedure Show; override;
      public
        constructor Create(AOwner: TComponent); override;
        function Activate: T;
        property Frame: T read FFrame;
      end;
    
    implementation
    
    { TTabItemFrame }
    
    constructor TTabItemFrame<T>.Create(AOwner: TComponent);
    begin
      inherited;
      Text:= T.GetTitle;
      Visible:= False;
    end;
    
    function TTabItemFrame<T>.Activate: T;
    begin
      Visible:= True;
      TabControl.ActiveTab:= Self;
      Result:= FFrame;
    end;
    
    procedure TTabItemFrame<T>.Hide;
    begin
      inherited;
      FFrame.DisposeOf;
      FFrame:= nil;
    end;
    
    procedure TTabItemFrame<T>.Show;
    begin
      inherited;
      FFrame:= T.Create(Self);
      FFrame.Parent:= Self;
    end;
    
    end.
    
    ---------------------------------------------------------------------
    
    type
      TFrameA = class(TFrameBase)
        Label1: TLabel;
      public
        class function GetTitle: string; override;
      end;
    
    implementation
    
    // if it's necessary to access components or methods of
    // any other frame or the main form directly
    uses
      _FormMain;
    
    //...
    

    更新:我决定在FMX应用程序中使用表单而不是框架,因为框架在设计时不能使用样式。一个副作用是,我可以使用表单标题作为选项卡标题,而不是类函数。

    将表单嵌入tabitem有点棘手:

    constructor TFormTabBase.Create(AOwner: TComponent);
    begin
      inherited;
      while ChildrenCount > 0 do Children[0].Parent:= AOwner as TTabItem;
    end;
    
    procedure TTabItemForm<T>.Show;
    begin
      inherited;
      FFormTab:= T.Create(Self);
      Text:= FFormTab.Caption;
    end;