1
votes

I'm using VFI (Visual Form Inheritance) and I need to check if a component of an instantiated form belongs to the formclass or to the form superclass.

any ideas ?

  unit1

  TFormStatus = class(TForm)
    cpPanel: TPanel;
    lblStatus: TLabel;
  end;

  unit 2

  TFormCodigo = class(TFormStatus)
    lblCodigo: TLabel;
  end;

  frmCodigo: TFormCodigo:

In any instances of frmCodigo I want to detect that lblCodigo is local to TFormCodigo and cpPanel / lblStatus are inherited components;

  for i:=0 to Self.ComponentCount-1 do begin        
      if "InheritedComponent" (Self.Components[i]) then ...
  end;

Something like this is possible using RTTI for object properties, but I dont know if it is possible for components.

Thanks.

3
The real question is: Why do you want to know? I'm sure there are "proper" OO solutions to the problem behind this question. (Most probably virtual methods.)Uli Gerhardt
@Ulrich Well, the OP may be working on some framework-like code that wants to self-inspect. But yes, I'd be curious to understand the motivation behind the question.David Heffernan
@David: The posted code looks very "concrete" - no framework in sight. :-)Uli Gerhardt
It seems to me that any solution that doesn't look in the DFM resource will be incomplete. It's possible to have components defined in the DFM that are not stored in any field of the class. (Just clear the Name property in the Object Inspector.) Such a component won't appear in the class definition, but I assume you'd still want to know which form class contributed that control to the final instance.Rob Kennedy
If you're willing to take the hacky way, you can use Hallvard Vassbotn's findings on his "published fields details" article to find out which component belongs to which class.Sertac Akyuz

3 Answers

1
votes

If I understand you correctly, you need TRttiMember.Parent. For example see this article by Rob Love. You'll need Delphi 2010 or later I think.

In fact this is just part of an excellent series of articles - these articles will also tell you how to get hold of the fields, properties etc. without having to know their names.

0
votes

Maybe something "stupid" like

function TFormStatus.IsStatusComponent(AComponent: TComponent): Boolean;
begin
  Result := (AComponent = cpPanel) or (AComponent = lblStatus);
end;

already fulfils your needs?

0
votes

In your TFormCordigo you can override ReadState method that is called every time a resource is read for a particular form. After inherited called ComponentCount contains the number of components created up to the current member of hierarchy, so after all you have list of borders for components that you can save elsewhere.

The code below illustrates this approach

procedure TInhTestForm.Button3Click(Sender: TObject);
var
  i: integer;
begin
  inherited;

  Memo1.Lines.Clear;
  for i:=0 to ComponentCount-1 do
  begin
    Memo1.Lines.Add(format('%s inroduced in %s', [Components[i].Name, ComponentParent(i).ClassName]));
  end;
end;

function TInhTestForm.ComponentParent(Index: integer): TClass;
var
  i, j: integer;
begin
  Result:=Nil;
  for i:=Low(fComponentBorders) to High(fComponentBorders) do
  begin
    if Index <= fComponentBorders[i] - 1 then
    begin
      j:=i;
      Result:=Self.ClassType;
      while j < High(fComponentBorders) do
      begin
        Result:=Result.ClassParent;
        Inc(j);
      end;
      break;
    end;
  end;
end;

procedure TInhTestForm.ReadState(Reader: TReader);
begin
  inherited;
  SetLength(fComponentBorders, Length(fComponentBorders) + 1);
  fComponentBorders[High(fComponentBorders)]:=ComponentCount;
end;