DDeberla
DDeberla

Reputation: 87

( Delphi fmx ) Can you create UI controls in a background thread without blocking user interface

I'm wondering if it's possible to create UI elements , even a complete form, in a background thread ( "without using it of course" ) , and once it's done, make it available in main thread to be shown.

It's relatively easy now to separate time consuming data operations in background threads and synchronize the results with your main thread but what if creating the UI itself IS the time consuming operation ?

If possible, you could maybe have a fast startup screen and then start a background thread to create a set of forms. Whenever one is ready, it enables a menu item in the main thread so that it can be used.

I tried simple code, but it freezes immediatly. Is it possible ?

Execute in main program :

    ...
    // declare var in main form 
    public
     { Public declarations }
     lForm : TForm ;

    ...
    // Execute e.g. with button click in main form 
    TThread.CreateAnonymousThread( procedure begin
    // this stops application from running when the form is show
    // in the synchronize part
    lForm := TForm1.Create(Self);

    TThread.Synchronize(nil,
     procedure begin
       // This does not stops the application but freezes the gui of course
       //lForm := TForm1.Create(Self);
       lForm.Parent := Self ;
       lForm.Show ;
      end );

   end ).Start ;`


    procedure TForm1.FormCreate(Sender: TObject);
    begin
     sleep(2000);
    end;
    ...



If it's not possible, how could you do this in the main thread while still 'simulating' that your main thread is responsive ? ( by calling something like application.processmessages regularly or so ? )

I'm using Delphi Rio 10.3, fmx framework.

Upvotes: 2

Views: 1038

Answers (3)

DDeberla
DDeberla

Reputation: 87

So , in summary, UI controls can only be used safely in the thread they are created in, and you can't change this behaviour after their creation time ( and make them 'belonging' to another thread as if they were created there in the first place ).

It might be though that conceptually, creating forms, that do not interact with another can work looking at
How to make a form in a DLL embedded inside my application?
I'm assuming that also here, the form is indeed created in different thread , probably even in a different process, right ?

Upvotes: 0

Dalija Prasnikar
Dalija Prasnikar

Reputation: 28517

I'm wondering if it's possible to create UI elements , even a complete form, in a background thread ( "without using it of course" ) , and once it's done, make it available in main thread to be shown.

NO.

Creating and accessing UI controls from background thread is not thread safe.

While you can create some proof of concept code that seemingly works, such code is inherently broken. It may fail randomly.

Upvotes: 3

DDeberla
DDeberla

Reputation: 87

I found that the following does not freeze instantly, but if that's pure luck for now or wisdom, I'm unsure..
Instead if making the form visible in the synchronize part of the background thread, I do it 'really' in the main thread...

( I could understand that as long as you don't give any parent to UI controls, they are 'safe'. How would the main thread know about their existence ? )

I might test this a bit further afterall.

procedure TTabbedForm.Button1Click(Sender: TObject);
begin


 TThread.CreateAnonymousThread( procedure begin
    lForm := TForm1.Create(Self);

    TThread.Synchronize(nil,
     procedure begin
       //lForm.Parent := Self ;
       //lForm.Show ;
       Button2.Enabled := True ;
      end );

   end ).Start ;

end;

procedure TTabbedForm.Button2Click(Sender: TObject);
begin
 if Assigned(lForm) then begin
  lForm.Parent := Self ;
  lForm.Show ;
 end;

end;


Upvotes: -1

Related Questions