Reputation: 87
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
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
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.
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
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