1

an example, I need to do this to solve a problem in a framework I am developing :

//Unit2 :
    procedure A(aForm : TForm; AClassType: TFormClass); 
    begin 
       ShowMessage (AClassType(aForm).edtUser.text);
    end; 

    ...

//Unit1 :

    Uses Unit2;

    begin
       form1 := TForm1.Create;
       Try  
          A(form1, TForm1); 
       Finally
          form1.Free;
       End;
    end;

The compiler does not accept this line:

AClassType (aform).edtUser.text

One solution would be to use:

Uses
    UnitofTForm1;

The procedure (aform: TForm; AClassType: TForm1);
begin
    ShowMessage (AClassType (aform).edtUser.text);
end;

But I can not do so because they are giving circular reference and I need some decoupling in my framework

Is there any way to make typecast passing as parameter the type of form or is there another way to do this ?

2
  • Do you have multiple, different TFormxxx classes? Are they all derived from the same base class? Commented Jun 10, 2015 at 19:50
  • Yes i have multiple Tformxx Classes and they derived from TForm Commented Jun 10, 2015 at 19:59

1 Answer 1

3

What you are asking for can be done by either:

  1. deriving the various Form classes from a common base class that exposes the field you want to access:

    procedure A(aForm : TBaseForm); 
    begin 
      ShowMessage(aForm.edtUser.Text);
    end; 
    

    type
      TBaseForm = class(TForm)
        edtUser: TEdit;
        ...
      end;
    
      TDerivedForm = class(TBaseForm)
        ...
      end;
    
    ...
    
    frm := TDerivedForm.Create;
    try  
      A(frm); 
    finally
      frm.Free;
    end;
    
  2. or, use Generics:

    type
      TBaseForm = class(TForm)
        edtUser: TEdit;
        ...
      end;
    
      TMyClass = class
        class procedure A<T: TBaseForm>(aForm : T); 
      end;
    
    class procedure TMyClass.A<T>(aForm : T); 
    begin 
       ShowMessage(aForm.edtUser.Text);
    end; 
    

    frm := TDerivedForm.Create;
    try  
      A<TDerivedForm>(frm); 
    finally
      frm.Free;
    end;
    
  3. if a common base class is not possible, use an interface instead:

    type
      IMyFormAccess = interface
        function GetUserText: string;
      end;
    
    procedure A(aForm : IMyFormAccess); 
    begin 
      ShowMessage(aForm.GetUserText);
    end; 
    

    type
      TForm1 = class(TForm, IMyFormAccess)
        ...
        function GetUserText: string;
        ...
      end;
    
    function TForm1.GetUserText: string;
    begin
      Result := edtUser.Text;
    end;
    
    ...
    
    frm := TForm1.Create;
    try  
      A(frm as IMyFormAccess);
    finally
      frm.Free;
    end;
    
  4. or, use legacy RTTI (only works with published properties):

    uses
      TypInfo;
    
    procedure A(aForm : TForm); 
    var
      Edt: TEdit;
    begin 
      Edt := TEdit(GetObjectProp(aForm, 'edtUser', TEdit));
      if Edt <> nil then
        ShowMessage(Edt.Text);
    end; 
    

    frm := TForm1.Create;
    try  
      A(frm);
    finally
      frm.Free;
    end;
    
  5. or, use extended RTTI (works with all fields and visibility):

    uses
      System.Rtti;
    
    procedure A(aForm : TForm); 
    var
      Ctx: TRttiContext;
      Fld: TRttiField;
      Value: TValue;
      Edt: TEdit;
    begin 
      Fld := Ctx.GetType(aForm.ClassType).GetField('edtUser');
      if Fld <> nil then
      begin
        Value := Fld.GetValue(aForm);
        if (not Value.IsEmpty) and Value.IsObject then
        begin
          Edt := Value.AsObject as TEdit;
          ShowMessage(Edt.Text);
        end;
      end;
    end;
    

    frm := TForm1.Create;
    try  
      A(frm);
    finally
      frm.Free;
    end;
    
Sign up to request clarification or add additional context in comments.

3 Comments

I wil try some of these methods and return, Thanks
I analyzed all the ways, the last is the one that will solve my problem, but it seems to have 1 error. Field Fld is never initialized and results in runtime error Adress Violation. Can you see what is missing in the latest code?
I fixed the error. It was just a typo, Value := should have been Fld := when calling TRttiType.GetField().

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.