1

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.

DDeberla
  • 77
  • 5
  • 1
    Creating UI controls is not your bottleneck – David Heffernan Oct 25 '19 at 07:12
  • "*what if creating the UI itself IS the time consuming operation ?*" - then you have a severely bad UI design – Remy Lebeau Oct 25 '19 at 07:42
  • Although the question was generic ( I can think of some use cases ) , my current 'real life' problem is with twebbrowser..Creating it does indeed not take a lot of time, but setting the URL to a local html file with embedded video tags does take few seconds to load. So ideally, this happens in the background and is shown whenever ready ( It maybe does not block the UI, but for sure it flickers...) – DDeberla Oct 25 '19 at 07:52
  • Why would pre creating forms in the background on idle time be a bad design ? ( for even yet slightly more faster response time when using it ) – DDeberla Oct 25 '19 at 07:56
  • To be clear : I'm not talking about loading the main form in background ( but all kinds of other supporting forms ) – DDeberla Oct 25 '19 at 07:59
  • 1
    @DDeberla Why aren't you creating these supporting forms on demmand instead right after application start. Creating forms before they are neded is just wasting memory. – SilverWarior Oct 25 '19 at 09:45
  • 1
    I'd be surprised if the web page load could be offloaded to a separate thread. But if that's what you want to do, ask about that. It looks like you asked about creating controls and forms, but in fact you want to offload something else altogether. Namely the loading of the page. – David Heffernan Oct 25 '19 at 10:07
  • I appreciate all the comments, but the question is indeed what I wanted to know. I gave 1 example but that doesn't mean that the example replaces the question. I'm checking what are the boundaries of optimizing form loading times when sticking to Delphi. @SilverWarior : If the benifits ( instant display when needed ) outperform the penalties ( memory consumption ) is really application dependant. But you are right, usually not. But this time, I'm not usual :-) – DDeberla Oct 25 '19 at 11:25
  • I guess that with the given answers, the answer is : No, it's not possible. – DDeberla Oct 25 '19 at 11:28
  • Well I suppose I was wondering whether you wanted to know anything useful, or whether it is just an academic question. Because creating controls is not your bottleneck. Well, I think so. Did you benchmark to prove me wrong? – David Heffernan Oct 25 '19 at 17:13
  • 1
    [Some related reading](https://github.com/djjd47130/DelphiThreadDemo/blob/master/README.md). Neither VCL or FMX are thread-safe. – Jerry Dodge Oct 26 '19 at 21:57
  • Thank you all for usefull comments, esepcially with some background on the 'why'. So the answer is 'No' . – DDeberla Oct 27 '19 at 14:23

3 Answers3

3

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.

Dalija Prasnikar
  • 27,212
  • 44
  • 82
  • 159
0

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 ?

DDeberla
  • 77
  • 5
  • 1
    No. UI controls must be created and used from the main thread. And that post you linked to says nothing about cross thread or cross process UI. – David Heffernan Oct 30 '19 at 06:18
-1

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;


DDeberla
  • 77
  • 5
  • No, it is not safe even if you don't give it parent... it can be safer as it will fail less often, but it is broken code that may fail randomly. – Dalija Prasnikar Oct 25 '19 at 12:05
  • *"How would the main thread know ... ?"* Also, how would them know about the main thread? I don't exactly know what is meant by safe but if it is that you don't receive an immediate exception, expect that there should be other consequences of this setup. F.i., on windows at least, enumerating thread windows will exclude windows that you'd want to be enumerated and so you should observe behavioral fail of topmost forms, or modal forms. The framework assumes it's on a single thread, it's simple as that. – Sertac Akyuz Oct 25 '19 at 12:41