Search code examples
delphifiremonkeydelphi-xe6firemonkey-fm3

Focus TEdit on a Dynamically loaded Embedded Form Firemonkey


I have a application which load plugins that are in the form of bpls. Each plugin contains a form to be embedded into another package called CoreInf (form name ManageF) which is just the base gui of the application that contains a TTabcontrol known as MTabcontrol1. Here basically what happens

A list of plugins are dynamically loaded at runtime in sequential order to layout the interface. It loads the plugins based on the interface IPluginFrame(Shared.bpl) . If it contains the interface it then tries to create a new tab in MTabcontrol1 and embedded the form. What im trying to do is make a dynamically created speedbutton onClick focus a TEdit box on a specific ebedded form but it keeps coming up as access violation errors.

Shared.bpl that contains the interface

unit PluginIntf;

interface

uses
  FMX.Types, FMX.Controls;

type
  IPluginFrame = interface
  ['{3B4943DB-951B-411B-8726-03BF1688542F}']
    function GetBaseControl: TControl;
  end;


implementation

end.

Form and Button that is to be ebedded into the interface

InventoryInf.pas has the form to be embeeded

    var
      InventoryF: TInventoryF;

    implementation

    {$R *.fmx}

    function TInventoryF.GetBaseControl: TControl;
    begin
      Result := InvenLayout;  //<---- This is a a TLayout which align 
                              //to client this is the parent of every item on form
    end;

    //Below is the on click event for the TSpeedButton invBtn 
    //Which looks for the embedded form that is embedded
   //in MTabcontrol1 as a TTabitem that has the name InventoryF 

    procedure TInventoryF.Look4Tabitem(Sender: TObject);
    var
     o : TTabitem;
     s :TEdit;
    begin
     o  := TTabitem(ManageF.MTabcontrol1.FindComponent('InventoryF'));

     ManageF.MTabcontrol1.ActiveTab := o;

    s  := TEdit(ManageF.MTabcontrol1.FindComponent('VendorF').FindComponent('SearchEdit1')); <-- Dont  think it actually found the TEdit                               

    s.Setfocus;  <------------------ Not focusing giving access violtaion error

      with DataConModule1.InventoryQuery do
      ...   


    end;

TSpeedButton invBtn that is injected into Panel to the side

unit InjectedInvBtn;
interface
implementation
uses
  FMX.Types, InventoryInf, FMX.Controls, FMX.Forms, InjectedControlsHelper, FMX.StdCtrls,
  ManageInf;
var
  SysBtn: TSpeedButton;
initialization
  SysBtn := TInjectedControl<TSpeedButton>.Create;
  SysBtn.Align := TAlignLayout.Top;
  SysBtn.Name := 'invBtn';
  SysBtn.Text := 'INVENTORY';
  ManageF.MenuPanel.AddObject(SysBtn);
  SysBtn.OnClick := InventoryF.Look4Tabitem;
end.

**ManageF Showing how it loads the forms into tabs MTabControl1 **

uses Shared;


function IsPluginFrameClass(AType: TRttiType; var AFormClass: TCustomFormClass): Boolean;
var
  LClass: TClass;
begin
  if not (AType is TRttiInstanceType) then Exit(False);
  LClass := TRttiInstanceType(AType).MetaclassType;
  Result := LClass.InheritsFrom(TCustomForm) and Supports(LClass, IPluginFrame);
  if Result then
    AFormClass := TCustomFormClass(LClass);
end;


function TSettingsF.LoadPluginTabs(const AFileName: string): HMODULE;
var
  Context: TRttiContext;
  Frame: TCustomForm;
  FrameClass: TCustomFormClass;
  LType: TRttiType;
  Package: TRttiPackage;
  Tab: TTabItem;
 // Statusbar: TTabItem;
  //Butz: TButton;
begin
  Result := LoadPlugin(AFileName);
  try
    { Cycle through the RTTI system's packages list to find the one we've just loaded. }
    for Package in Context.GetPackages do
      if Package.Handle = Result then
      begin
        { Cycle through the package's types looking for implementors of the
          IPluginFrameinterface defined in the shared package. }
        for LType in Package.GetTypes do
    if IsPluginFrameClass(LType, FrameClass) then
          begin
            { For each frame, create a new tab to host its contents. In the case of
              a VCL application, we could require an actual TFrame object, or failing
              that, embed the form directly. FireMonkey has neither frames proper nor
              supports embedded forms, so instead we ask the implementing form to
              nominate a base control that will get embedded. }
            Tab := TTabItem.Create(ManageF.MTabcontrol1);
            Frame := FrameClass.Create(Tab);
            Tab.Text := ' ' + Frame.Caption;
            Tab.Name := Frame.Name;

            MyTablist.Add(Tab);


            (Frame as IPluginFrame).GetBaseControl.Parent := Tab;
            { Associate the tab with the plugin - since it owns the 'frame' form,
              and that form owns its own components, freeing the tab will have the
              effect of freeing all the actual plugin objects too. }
            RegisterPluginComponent(Result, Tab);
            ManageF.MTabcontrol1.AddObject(Tab);
            Tab.Width := Tab.Canvas.TextWidth(Tab.Text + 'w');

          end;

           if IsStatusFrameClass(LType, FrameClass) then

           begin

           ....

            { Associate the tab with the plugin - since it owns the 'frame' form,
              and that form owns its own components, freeing the tab will have the
              effect of freeing all the` actual plugin objects too. }
           // RegisterPluginComponent(Result, Statusbar);
          //  ManageF.StatusMenuPanel1.AddObject(Statusbar);
            //Statusbar.Width := Statusbar.Canvas.TextWidth(Statusbar.Name + 'w');



           end;
        Break;

     end;
  except
    UnloadPlugin(Result);
    raise;
  end;
end;

Hope i illustrated the problem properly. Please Help =(


Solution

  • Found a work around by looping through the components of the Tcustomform that is embedded. Here is what i did.

    instead of TEdit i used a tms edit box TTMSFMXSearchEdit

    procedure TVendorF.focuscheck;
    var
      i: integer;
      j: integer;
      Fieldname: string;
      o : TTabitem;
      e : TTMSFMXSearchEdit;
    begin
      if ManageF.MTabcontrol1.FindComponent('VendorF').Name = 'VendorF' then
        begin
        o  := TTabitem(ManageF.MTabcontrol1.FindComponent('VendorF'));
    
       //ShowMessage(IntToStr(o.ComponentCount)) ;
       // ShowMessage((o.Components[0].tostring));
    
          for i := 0 to ManageF.MTabcontrol1.ActiveTab.ComponentCount - 1 do
            if (ManageF.MTabcontrol1.ActiveTab.Components[i]) is TCustomForm then
              begin
             // ShowMessage('TCustomForm Recognized gonna look for child components now');
             // ShowMessage(IntToStr(ManageF.MTabcontrol1.ActiveTab.Components[i].ComponentCount));
    
            for j := 0 to ManageF.MTabcontrol1.ActiveTab.Components[i].ComponentCount - 1 do
                    if (ManageF.MTabcontrol1.ActiveTab.Components[i].Components[j]) is TTMSFMXSearchEdit then
                       begin
                       // ShowMessage('Edit box found =)')
                            if (ManageF.MTabcontrol1.ActiveTab.Components[i].Components[j].Name = 'VenSearchEdit1') then
                               begin
                               //ShowMessage('Edit1 box found =)');
                               //ShowMessage('See if we can focus it');
                               e := TTMSFMXSearchEdit(ManageF.MTabcontrol1.ActiveTab.Components[i].Components[j]) ;
                               e.SetFocus;
                               end;
    
                    end;
            end;
       end;
    end;
    

    Its a little sloppy but it works =). If anyone else got a better way let me know