Search code examples
delphitabcontroltabcontainer

How to interact with non stored child controls in FMX design time? (TTabControl Tab Content)


I have been scanning the code of TTabControl for the past three days and I found the following:

  1. The control will accept child controls but redirect them based on the state it is in, for example: if the child is a TTabItem it will assign it to the FContent: TContent which is used as a tabs container, otherwise if the child is a special control (TEffect, TAnimation ...) it will be added to the TTabControl else if there is an active tab the child will be redirected to that, else it will be redirected to FNoItemsContent: TContent non visible control (no idea why!!!).
  2. when the child is redirected to the active tab, it will be redirected to the FContent: TContent member of the tab (in design time the position will be adjusted).

the meaning of the word redirected here is which parent will the child be assigned to.

So Child.Parent := TabControl; triggers the above and this is the method that does that.

procedure TTabControl.AddOrInsertObject(const AObject: TFmxObject; const Index: Integer = MaxInt);

what is confusing me is that the following are non stored Controls but they are parents in design and runtime for the child.

  • TTabItem.FContent.
  • TTabControl.FContent.
  • TTabControl.FNoItemContent.

the TTabItem is stored, so in the IDE when you add a tab (right click add new TabItem), you will see in the structure panel that the TTabItems are children of the tab control, drop another control and you will see that it is child of the active tab (The TTabItem and not its FContent).

you can interact with the controls and all.

My question

What is the idea behind this mechanism, how to do the same if I want to make it from scratch?

What I want is the design time feature.


Solution

  • I see that the code overrides both DoAddObject and DoInsertObject, calling AddOrInsertObject from both, with Add not passing Index so it uses the default from the latter method which is MaxInt.

    In that method it writes:

    // If AObject is TabItem, then we add it to the tab items container (FContent)
    // If AObject is Effect, Animation, Style resource, we add it to the Self
    // In all other cases, we add AObject to active tab or special container (FNoItemsContent)

    taking it from the bottom up:

    obviously the FNoItemsContent is used when the TTabControl has no tabs to add/insert the child to

    it is like a delegation pattern I think that they're using so that you can interact with the TTabControl itself and it passes it on to current tab if available (except for Effect, Animation, Style special objects that are to be added to the TTabControl itSelf)

    of course if you try to add a TTabItem it will be added to the tabs collection (tab items container, aka FContent)