Threads and UI Interaction

I have a method that loops through a bunch of files and processes each file.
It take tiiiiiiimmmmmmeeeeee…

I want to throw up a progress bar in a modal dialog that can only be exited and causes the whole operation to be canceled.

I of course figured I would need to have my long method run in a MyThread.Run… Which would pop up a dialog window and then update the dialog progress bar for each iteration of its main loop. However I understand that interacting with UI elements from a thread is verboten.

What am I missing?

This webinar got me started with threads. It also shows how to do progress bars.
Threads

BTW, personally I prefer using Helper Apps in cases like yours. A bit more tricky but that way you use multiple cores. By default, your Xojo App (and it’s threads) run on a single core so (apart from your UI being more responsive) you’re not always getting the speed increase that you expect.

Timers. You can safely start any timer from any thread, and the Timer.Action event is guaranteed to run on the GUI thread. Whenever you need to update the GUI from a thread, just trigger the timer (and then yield so the GUI thread can run.) Give the Timer a Period of 1ms and a Mode of ModeSingle to have the Action event run only once and as soon as possible.

For a progress bar, your thread might store the progress value somewhere safe, trigger the timer, and read the value back and update the progressbar in Timer.Action.

Minor quibble
Timers run on the Main thread - theres no “GUI thread” - but the intent is basically the same
The same thing occurs in non-gui apps with threads & timers
You just do it in something like a console app for a different reason than to avoid accessing the UI

I consider the terms to be synonymous, but when discussing GUI access from a Thread, “GUI thread” is clearer.

main thread is more accurate & correct in general
As I said, its a minor quibble about terminology

Why can’t a subclass of thread define events that are handled by the window that has the thread?

They sure can. Just have the thread create a timer, bind to the timer’s action event, and raise your event there. If you use a 1 period timer, the event will trigger on the next iteration of the main even loop.

Also see the Task example class.

Cool.
I just had a little trouble Raising the Event.
MyThread::Thread.

I define an event called Starting
In my run method ( I know I should do this in my threads timer action event) implementation I say RaiseEvent Starting
I see that the command line completion for Starting works… (So I think the compiler will be happy.)
Yet when I compile it is not happy with the RaiseEvent Line.

Need a little more information than that. What you’ve described should work. And while it will work, that even will be fired inside the thread, so it must follow the same no-UI rules. That’s what the timer is for.

In the following edition of xDev I talk about using an in-app notification center for doing just this, as well as handling a variety of other scenarios.

https://gumroad.com/l/DXbT

Because the class which is a thread will be accessing the UI and trigger an exception.

Just try to wrap your head around using a timer and you will be fine.