Search code examples
delphiframefiremonkeytabcontroltlist

How a TList can get the input value from a Frame's TEdit/TCombobox


The Main form contains TTabControl which can create some tabs, dynamically. Whenever I add a new tab, a frame is created and add into the new tab. And finally, I will save all these TTabItem into a TList.

TForm1 = class(TForm)
  TabControl1: TTabControl;

procedure TForm1.AddNewTab;
var
  profileFrame :TProfileFrame;
begin
  profileFrame := TProfileFrame.Create(Self);

  //TabItem
  TabItem := TabControl1.Add();
  inc(tab_name_Count);
  tabItem.Text := tab_name_Count.ToString;
  //
  profileFrame.Parent := tabItem;
  tablist.Add(TabItem);
end;

And this is my frame:

TProfileFrame = class(TFrame)
 Name: TEdit;
 Gender: TComboBox;

Finally, how can I get the (Name) and (Gender) value in the frame, and print it out in main form? If let say i created 4 tabs, each tabs has its own frame, how can i get the value from different frame?? Im super confuse and new to Delphi.


Solution

  • The main problem is your frames' variable are procedure local variable.

    I see different ways to solve your problem.

    First: using TObjectList:

    uses ..., System.Generics.Collections;
    
    TForm1 = class(TForm)
      TabControl1: TTabControl;
    private
      FFrames:TObjectList<TProfileFrame>;    
    
    procedure TForm1.AddNewTab;
    var
      profileFrame :TProfileFrame;
    begin
      //TabItem
      TabItem := TabControl1.Add();
      profileFrame := TProfileFrame.Create(TabItem); 
      inc(tab_name_Count);
      tabItem.Text := tab_name_Count.ToString;
      profileFrame.Parent := tabItem;
      if not assigned(FFrames) then
        FFrames := TObjectList<TProfileFrame>.Create(false); //we don't need ObjectList to own Frame, I suppose, so we have to pass `false` into Create method
      FFrames.Add(profileFrame);
      tablist.Add(TabItem);
    end;
    
    //Just to demonstrate how to get value from frame
    function TForm1.GetGenderFromFrame(ATabItem:TTabItem):String;
    var i:integer;
    begin
      result := '';
      if FFrames.Count > 0 then
      for i := 0 to FFrames.Count - 1 do
        if FFrames[i].TabItem = ATabItem then
        result := FFrames[i].Gender.Selected.Text;
    end;
    

    Or you can use another way (checked on Delphi 10.1 FMX Project). You have to change your procedure like this:

    procedure TForm1.AddNewTab;
    var
      profileFrame :TProfileFrame;
    begin  
      //TabItem
      TabItem := TabControl1.Add();
      profileFrame := TProfileFrame.Create(TabItem);
      inc(tab_name_Count);
      tabItem.Text := tab_name_Count.ToString;
      //
      profileFrame.Parent := tabItem;
      tablist.Add(TabItem);
    end;
    

    Now your frame has owner: TabItem. And TabItem has components. We can use it:

    function TForm1.GetGenderFromFrame(ATabItem:TTabItem):String;
    var i:integer;
    begin
      result := '';
      if ATabItem.ComponentCount > 0 then
      for i := 0 to ATabItem.ComponentCount - 1 do
        if ATabItem.Components[i] is TProfileFrame then
        result := (ATabItem.Components[i] as TProfileFrame).Gender.Selected.Text;
    end;
    

    P.S. You can use for ... in ... do instead of for ... to ... do, it can be better, but it's up to you.