Jump to content
Sign in to follow this  
dormky

Can the UI be updated in any way while the main thread is doing work ?

Recommended Posts

I've tried calling Application.ProcessMessages from a thread, that didn't work. Had to try it lol.

 

My goal is to have a loading gif playing while the work is ongoing. The work cannot be moved out of the main thread, as this would require rewriting multiple thousands of lines of code, which is sure to create bugs (especially as this deals with COM ports).

 

Any ideas ?

Share this post


Link to post

To have effect you should call Application.ProcessMessages from the main thread while the work is done. This will open a can of worms but at least will work somehow. Otherwise you need to move the work in a thread.

Share this post


Link to post
Just now, Cristian Peța said:

To have effect you should call Application.ProcessMessages from the main thread while the work is done. This will open a can of worms but at least will work somehow. Otherwise you need to move the work in a thread.

Going around a bunch of files inserting calls to ProcessMessages in mostly random places (the work is not deterministic) seems like a magnificient way of shooting both feet at the same time 😕

Share this post


Link to post
Just now, dormky said:

I've tried calling Application.ProcessMessages from a thread, that didn't work. Had to try it lol.

 

My goal is to have a loading gif playing while the work is ongoing. The work cannot be moved out of the main thread, as this would require rewriting multiple thousands of lines of code, which is sure to create bugs (especially as this deals with COM ports).

 

Any ideas ?

The answer is no since the update would have to be triggered somewhere from inside the work code.

But you can create and show a window from a secondary thread, it is just a bit cumbersome to do since the visual part of the VCL is not thread-safe. The secondary thread needs a message loop that will process all messages for the window, including timers and paint messages. The simplest way to get that loop is to show the window modally.  And the safest way to do such stuff is to not use a Delphi form but do it all the API way (hence the cumbersome part above 8-)).

If you want to use a Delphi form the important points to mind are:

  • Do not autocreate the form!
  • Create the form inside the Execute method of the secondary thread, using Nil as owner. Use a try finally block to make sure the form is destroyed. Use a field of the thread class to store the form reference.
  • ShowModal the form.
  • Add a public method to the thread class the main thread can call to get the form to close once the work is done. The method should set the form's ModalResult to mrCancel to allow the modal loop to exit normally.

Share this post


Link to post

One option: Create another application that shows a loading GIF and occasionally send it messages from your main thread to update/exit/etc. Has drawbacks but disturbs the exiting application the least code and UI wise.

Share this post


Link to post
30 minutes ago, PeterBelow said:

The answer is no since the update would have to be triggered somewhere from inside the work code.

But you can create and show a window from a secondary thread, it is just a bit cumbersome to do since the visual part of the VCL is not thread-safe. The secondary thread needs a message loop that will process all messages for the window, including timers and paint messages. The simplest way to get that loop is to show the window modally.  And the safest way to do such stuff is to not use a Delphi form but do it all the API way (hence the cumbersome part above 8-)).

If you want to use a Delphi form the important points to mind are:

  • Do not autocreate the form!
  • Create the form inside the Execute method of the secondary thread, using Nil as owner. Use a try finally block to make sure the form is destroyed. Use a field of the thread class to store the form reference.
  • ShowModal the form.
  • Add a public method to the thread class the main thread can call to get the form to close once the work is done. The method should set the form's ModalResult to mrCancel to allow the modal loop to exit normally.

I thought about this, but dismissed the idea as this would mean the loading gif is dissociated from the window in which the loading occurs. If the window gets resized, moved, minimized or simply if the user opens up another program in that screen space that form is in trouble (ie will not be kept visible only when the working window is visible, and centered within it).

Share this post


Link to post
1 hour ago, dormky said:

I thought about this, but dismissed the idea as this would mean the loading gif is dissociated from the window in which the loading occurs. If the window gets resized, moved, minimized or simply if the user opens up another program in that screen space that form is in trouble (ie will not be kept visible only when the working window is visible, and centered within it).

This seems like adding requirements covering corner cases or minutiae that are unlikely to be meaningful to actual users. Most just dislike doubt and uncertainty - is it still doing anything? did it freeze? How much longer will it take? - provide some indication that answers those questions and most users will be happy. Trying for a precise UI treatment while also not fixing threading in the main application seems like a way to waste a lot of time on a secondary issue - just get the information displayed.

Share this post


Link to post
40 minutes ago, Brian Evans said:

This seems like adding requirements covering corner cases or minutiae that are unlikely to be meaningful to actual users. Most just dislike doubt and uncertainty - is it still doing anything? did it freeze? How much longer will it take? - provide some indication that answers those questions and most users will be happy. Trying for a precise UI treatment while also not fixing threading in the main application seems like a way to waste a lot of time on a secondary issue - just get the information displayed.

I'm 100% agreeing with you. Management doesn't. Management wants a pretty loading icon without actually putting in the work 🙂

Imo the windows cursor does a perfectly fine job, we're talking ~10s loading time here.

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×