0

I am using the Spring4D mobile app demo code to instantiate the MainForm using the TContainer with a DelegateTo() method, as shown below. The code works fine to show the MainForm.

However, the TEdit on the MainForm does not have a blinking caret (cursor) until the button is clicked and then the Edit is focused again, or the entire app is deactivated and then reactivated.

Also, using the commented out line Application.CreateForm(TMainForm, MainForm); works fine for the blinking caret.

program MyMobileApp;

uses
  FMX.Forms,
  FMX.Platform,
  Spring.Container,
  System.StartUpCopy,
  uMainForm in 'uMainForm.pas' {MainForm};

{$R *.res}


procedure RegisterServices(const container: TContainer);
begin
  container.RegisterType<TMainForm>
    .Implements<TMainForm>
    .AsSingleton
    .DelegateTo(
      function: TMainForm
      begin
        // This forces form creation to be synchronous.
        // May or may not be called on certain platforms already by the FMX framework.
        // Android will call this prior sending the message but iOS won't.
        // May be called multiple times with no harm done.
        Application.RealCreateForms;
        Application.CreateForm(TMainForm, Result);
        // Create instance and assign MainForm
        // (would otherwise be done by Application.CreateMainForm)
        Application.MainForm := Result;
        // And make it visible  as this may not be set in the designer and
        // no window would be displayed
        Application.MainForm.Visible := True;
        Result := Result;
      end);

  container.Build;
end;

procedure ResolveMainForm(const container: TContainer);
begin
{$IFDEF MOBILE}
  // Platform service needs to handle that
  TMessageManager.DefaultManager.SubscribeToMessage(TApplicationEventMessage,
    procedure (const Sender: TObject; const M: TMessage)
    begin
      if M is TApplicationEventMessage then
        case TApplicationEventMessage(M).Value.Event of
          TApplicationEvent.FinishedLaunching: container.Resolve<TMainForm>;
        end;
    end);
{$ELSE}
  // This method works perfectly and the blinking caret appears fine in TEdit
  //Application.CreateForm(TMainForm, MainForm);    // <--- Blinking caret works fine

  // This method does not show the blinking caret in the TEdit unless the button is clicked
  // or application is deactivated/reactivated
  container.Resolve<TMainForm>;   // <--- Blinking caret does not work
{$ENDIF}
end;


var
  container: TContainer;
begin
  container := TContainer.Create;
  try
    Application.Initialize;
    RegisterServices(container);
    ResolveMainForm(container);
    Application.Run;
  finally
    container.Free;
  end;
  ReportMemoryLeaksOnShutdown := True;
end.

uMainForm.pas:

unit uMainForm;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.StdCtrls, FMX.Controls.Presentation, FMX.Edit;

type
  TMainForm = class(TForm)
    Edit1: TEdit;
    Button1: TButton;
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  MainForm: TMainForm;

implementation

{$R *.fmx}

end.

uMainForm.fmx:

object MainForm: TMainForm
  Left = 0
  Top = 0
  Caption = 'Form1'
  ClientHeight = 154
  ClientWidth = 227
  FormFactor.Width = 320
  FormFactor.Height = 480
  FormFactor.Devices = [Desktop]
  DesignerMasterStyle = 0
  object Edit1: TEdit
    Touch.InteractiveGestures = [LongTap, DoubleTap]
    TabOrder = 0
    Position.X = 40.000000000000000000
    Position.Y = 16.000000000000000000
  end
  object Button1: TButton
    Position.X = 40.000000000000000000
    Position.Y = 48.000000000000000000
    TabOrder = 1
    Text = 'Button1'
  end
end
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Rick Wheeler
  • 1,142
  • 10
  • 22
  • 2
    You should not call `Application.RealCreateForms`. This will be called by the FireMonkey framework at appropriate moment depending on the OS. This call will interfere with your form construction. – Dalija Prasnikar May 30 '22 at 06:19
  • If I take the `Application.RealCreateForms` line out then I get an `Access Violation`. I took this code directly from the Spring4D library as their suggested method to startup the `MainForm` for mobile apps. However cannot get the cursor/caret working properly for Windows desktop. – Rick Wheeler May 30 '22 at 21:53
  • 2
    You get the AV because you are working with the `MainForm` instance in the delegate and it is not constructed yet. I don't know what would be correct approach in this scenario, but calling `Application.RealCreateForms` is not a proper solution. Another question is why you want to use container for the `MainForm` in the first place. It is a rather special instance and on mobile platforms even more so, and any fiddling around it can create more problems than it solves. – Dalija Prasnikar May 31 '22 at 09:18
  • 2
    I am not responsible for 100% of the Spring4D source and certainly not for some mobile related demos - especially since within FMX so much changed over the years at some point it might have worked - forever people have asked about how to put the composition root of the DI container to the earliest point possible (i.e. mainform) and while there are some tricks and hacks around this - usually it's not the best approach exactly for the reason that the framework does some special stuff for that one form. Usually putting the composition root into the mainform code is a better way. – Stefan Glienke May 31 '22 at 09:45
  • Thankyou @DalijaPrasnikar and @StefanGlienke for your comments and insights. I will leave the `MainForm` creation as standard and move the composition root into the `MainForm` code as suggested. I've found everything works fine with the good old fashioned Delphi project startup so I'll leave it be without putting the `MainForm` into the composition root. Much appreciated. – Rick Wheeler May 31 '22 at 22:25

0 Answers0