Update UI while looping. Yes, Again

So, big loop.
Lots to do.
Desktop.
Mostly Windows…

How the heck do you get the screen to update and show a progress?
Either Windows starts complaining that the app is not responding and wants to kill it, or we try to use DoEvents which is a Bad Thing (and rarely solves the issue)

I have a nice graphic to show the progress - works fine on Mac, but doesnt update in Windows and after 18 years of using Xojo Im sick of this situation.
Surely there must be a way to do this ?
Games update the screen a lot more times per second than I need to.

a method call block the ui until your method exists.
therefore the unhandily thread class was created.
without this thread
instead of using for i = 1 to 1000
process this list in parts and let the app breathe.
as example a timer could fetch next small task from a list and process it.

in games the ui and game/physic “loop” are usually separate.

Not the kind of work that can be passed to many little timers.

have you an example what your “big loop” do?

My 2 cheater methods are:

  • CallDelegateOnMainThreadMBS AddressOf
  • xxxThreadSafeMBS

Have you tried using https://documentation.xojo.com/api/language/thread.html#thread-adduserinterfaceupdate and set your thread’s priority to something like “5”? (“normal priority”)

  1. Are you using a thread for your loop
  2. Are you using Control.Refresh to update your progress bar and have moved the control to the new Desktop types?

some areas,

for x as integer = 0 to 9999
for y as integer = 0 to 9999
//many interesting calcs
next
next

in another, the unpacking of 2000 small files as part of the initial installation, checking for presence of folders and dates of existing files

No.
For some of the things I need to do, I need the app to wait for the process to complete. I cant have things happening while a thread does its stuff.

And I don’t want to go anywhere near those pointless new Desktop types.
Do they have some new functionality I missed?

More like a change in functionality so I was just working out where you are before I offer some help, trying to figure out the best way to get you where you want to be as there may be a workaround without getting into a rewrite.

How are you telling your progress bar to update?
Is it on a canvas/control so Invalidate or Refresh?
Or are you using a progress bar control?

If I hone in on the specific instance I am trying to resolve now:

I have a tight loop for those files.
I open a window that has a progress bar and a canvas on it.
When the number of files MOD some number = 0, I issue

progwin.thecanvas.invalidate   (or refresh)
and
progwin.theprogressbar.invalidate (or refresh)

and I have tried app.doevents in there too.

Ive also moved the updates to the progress window:
I update a property in the loop, and have a timer on the progress window which fires every so often and tries to update the screen.

Also no effect.

Its my understanding that using a thread, I cannot affect the screen, so it seems Im stuck

in case of your loops
a single call would be “one interesting calc x,y”
after it is processed do the next from a prepared list.
you could also process for a second a bunch and then let the app response
a timer could trigger the next process.
Thread or Worker could be useful for you too.

using invalidate to much could result in nothing because windows ignore it.
and the method where you call it must end that the ui update comes.

Here’s how to do it:

I use this pattern all the time in my apps, and it works great.

3 Likes

Wll, @Mike_D won lol, what he said is the way to do in xojo

Another option is my Looper control. Drag it to the window and implement the events like HandleIteration, MoveNext, and Paused. It emulates what a Thread will do for you, but on the Main Thread and with finer control for updates.

3 Likes

Thanks for the ideas. Something to play with.
Sadly, I haven’t been able to actually use any Windows Xojo version after 2015 , so that Thread.adduserInterfaceupdate isnt available to me in this particular project.
New ones, yes.
But maybe the modal window that uses a timer to look at common properties which are affected by a thread…

In the case of tight loops, I find it really helps to add
#pragma DisableBackgroundTasks

to your methods, and then occasional calls to
App.SleepCurrentThread(1)

in the outer loop, e.g.
if x mod 1000 = 1 then App.SleepCurrentThread(1)
and play with the values here until you get a good combination of speed vs. UI responsiveness.

Thanks. I’ll take a look.

You can implement that same thing on a Thread class from that era. Subclass the thread, add a timer and when you need the UI to update you start the timer. The timer.Action always fires on the main thread. I queue a dictionary and pass whatever I have accumulated in the action event (again which fires on the main thread) and let the UI update then. There are various implementations of this floating around and if you need I can dig out my old BKSThread class that did this.

1 Like

There is no need for plugins (if one would not require them).

Cheating is pretty simple have an example here:
https://dutchhype.com/static/xojo/set_values_thread_safe.xojo_binary_project

This uses Timer.CallLater(0, delegate, value) to re-assign the given on the main thread even when called from any thread. This can be done with any control value.

It simplifies UI updating and makes stuff more readable (from the thread’s code).

1 Like