[Solved] ShowModal for an associated form


You added in the comments that you are setting FForm to be equal to a valid existing form. If so, you may not need to create anything:

procedure TMyComp.Execute_FormShowModal;
var
  frm: TFormUser;

begin
   frm:= TFormUser(FForm);

   frm.BtnOK.Enabled:=False;

   frm.ShowModal;
   //frm.Free;
end;

This assumes that this valid instance you are referring to is declared

type
   TFormUser = class(TForm)
      BtnOK : TButton;

      // etc...
   end;

If you trying to make a copy of the form you might use this:

procedure TMyComp.Execute_FormShowModal;

var
   frm: TFormUser;

begin
   frm:= TFormUser(TFormClass(FForm.ClassType).Create(FParentForm)); 

   // which is no different than:

   frm:= TFormUser.Create(FParentForm)); 

   frm.BtnOK.Enabled:=False;
   frm.ShowModal;
   frm.Free;
end;

If you want to manipulate the controls on the form (i.e. BtnOK), then you need to know the class type of the Form (TFormUser in this case). So it is contradictory to be required to know the exact class type of the form and yet want to instanciate a form from a design-time established type.


Since you may be trying to instanciate the form without “knowing” its absolute type, your FForm property should be the class for the form.

Assuming you weren’t publishing the “Form” property in your component, I would make these changes to your component:

TMyComp = class(TComponent)
   FFormClass : TFormClass;

   procedure SetFormClass(Value : TFormClass);
   property  FormClass: TFormClass read FFormClass write SetFormClass;

   procedure Execute_FormShowModal;
end;

The initialization code you referred to might look like this:

begin
  // .....

  //MyComp.Form := FormUser1;

  MyComp.FormClass := TFormUser;

  // .....

end;

And then “Execute_FormShowModal” becomes:

procedure TMyComp.Execute_FormShowModal;

var
   frm: TForm;

begin
   // Check that FFormClass is not nil and perform some alternate
   //  action.
   // if FFormClass = nil then ......
   //
   frm:= FFormClass.Create(FParentForm); 
   frm.ShowModal;
   frm.Free;
end;

Of course, you may also want to add some code to check if FFormClass is nil and preform some alternate behavior if so, like raise an exception or showing some message or even instanciating a default form.


If you were publishing the Form property then it won’t be able to handle the case where your FForm field value is nil because you don’t know or have a specific class type to instanciate the Form. That is:

frm:= TFormClass(FForm.ClassType).Create(FParentForm); 

will simply display a blank, empty form.


If you want to publish this property, you could try making it a string type that carries the name of the form class you want to instanciate and then use RTTI to find the class:

uses RTTI;

TMyComp = class(TComponent)
   FFormClassName : string;

   procedure SetFormClassName(const Value : string);
   property FormClassName: string read FFormClassName write SetFormClassName;

   procedure Execute_FormShowModal;
end;


procedure TMyComp.Execute_FormShowModal;

var
   frmCls : TFormClass;
   frm: TForm;

   RTTI : TRTTIContext;
   RTTIType : TRTTIType;

begin
   frmCls := nil;
   for RTTIType in RTTI.GetTypes do
      begin
         if (RTTIType.Name = FFormClassName) and (RTTIType.TypeKind = tkClass) then
            begin
               if RTTIType.Handle.TypeData.ClassType.InheritsFrom(TForm) then
                  begin
                     frmClass := TFormClass(RTTIType.Handle.TypeData.ClassType);
                     break;
                  end;
            end;
      end;

   // Check that frmCls is not nil and perform some alternate
   //  action.
   // if frmCls = nil then ......
   //
   frm:= frmCls.Create(FParentForm); 
   frm.ShowModal;
   frm.Free;
end;

8

solved ShowModal for an associated form