Event when a thread ends?

Hi
In the now deprecated Task class, there were events for the various states of the Task, importantly one called “Finished”

Xojo now recommend the use of the new Thread class with the UserInterface event. But it has no event to say the Thread is completed, and no way to add event definitions.

Can anyone suggest how to implement such a thing pls? I would like to set my thread off running in the background and have some event fire when it is done. My thread is now working fine (it is uploading a bunch of files to an FTP server) but notification when it is done would be great.

Many thanks
Mark

Why stop using Task class?
It can still be helpful.

Deprecated according to the Xojo docs.

So as I am developing now I am trying to avoid writing stuff that may need changing.

Am I being unnecessarily cautious?

I am fairly new to the world of Xojo so dont know the history and what their policy has been on how long things are deprecated before being removed.

What do you think?

Task class was in an example project. They now include an extra event in the thread class, but internally it’s also driven by a timer. I have no idea why they didn’t include a finished event.

1 Like

Yes it seems strange to remove useful functionality like those events when introducing new features…

Is it possible to create Events in the Thread somehow?

When the the ‘Run’ event is finished … well… the thread is finished. :slight_smile:

It’s great to have an event on main thread when worker thread is done.
I think task class did that.

1 Like

When the the ‘Run’ event is finished … well… the thread is finished. :slight_smile:

Well yes I suppose I could just wait around for the process in the thread to finish by keep checking it’s ThreadState value, but I can do that in the main code without even using a thread. What I was hoping to do was fire off the thread and give it a bunch of uploads to chew through in the background, meanwhile the main GUI is still usable. When the thread is finished it raises an event and I can do what is needed (Inform user, close down stuff etc etc)

It’s great to have an event on main thread when worker thread is done.
I think task class did that.

Yes it did. Task class had a number of events. But as I said, I am not using it as was concerned that the Task class is deprecated. Maybe I am being too cautious and it will be around for years to come.???

I have a class I developed called “ThreadwithFinishedEvent”

Basically when the thread ends, I have a timer with a period of 1 or 0 raise a finished event. It’s quite simple to do and with Xojo.Timer.CallLater you don’t even have to add a timer property to the thread or add any handlers.

Simply add the event definition to your subclass. Add a run event definition to the subclass as well. In the run method For the class call:

RaiseEvent Run
Xojo.Timer.CallLater(0, Address of ThreadFinished)

Where ThreadFinished is your finished event.

Very simple to do.

2 Likes

Hey Jon

That sounds exactly what I am looking for. I am a bit new to subclassing stuff, especially threads. Could I ask you for a bit more of an example pls? I think I see what you mean but not 100% sure. Thank you

It’s great to have an event on main thread when worker thread is done.
I think task class did that.

BTW Christian, as you know I have your MBS plugins, is there anything in there that does this? I am Mac only for my app so no need for anything x-platform.

Subclassing is a wonderful thing that once you get your head around, you will use it a lot. I remember when I couldn’t figure it out and how to implement events, etc.

So create a new class in your app. Set it’s super to Thread. Now you have a subclass of thread and you can simply add properties, methods, event definitions, etc.

So to help you understand, event definitions are things you define that are basically methods that run OUTSIDE of your class. So you raise one of these events you have defined and that allows code you put in wherever your class is used to be run specific to the needs there - make sense?

So the traditional Xojo thread has basically one event - Run. When you start the thread the run event is called.The user interface update is new but I had implemented my own a few years ago when Xojo removed the ability to update the user interface from threads.

So in my class I have added three new event definitions: Run - so that we can have your code wherever you need to place the thread run. ThreadFinished and UIUpdate.

I added two private properties in my class - both are timers. One if FinishTImer and one is UIUpdateTimer. Now these are not needed any longer with the advent of the Xojo.Timer.CallLater method, but I have also found actual timer objects seem to be more reliable. I’ve had a few issues over the years with CallLater and I am gun-shy.

I have three methods: FinishTimerAction, UIUpdateTimerAction and UpdateUI. The first two are private.

In the run event handled for my subclass I have the following code:

Sub Run() Handles Run
  FinishTimer = New Timer
  AddHandler FinishTimer.Action, AddressOf FinishTimerAction
  FinishTimer.Mode = Timer.ModeOff
  FinishTimer.Period = 0
  
  UIUpdateTimer = New Timer
  AddHandler UIUpdateTimer.Action, AddressOf UIUpdateTimerAction
  UIUpdateTimer.Mode = Timer.ModeOff
  UIUpdateTimer.Period = 0
  
  RaiseEvent Run
  
  FinishTimer.Mode = Timer.ModeSingle
  
End Sub

So when the thread starts running, it sets up the timers, it then raises its Run event so your code can execute. Once that code is finished, it then triggers the finish timer.

Here’s the methods for FinishTimerAction and UIUpdateTimerAction and UpdateUI:

Private Sub FinishTimerAction(t as timer)
  #Pragma Unused t
  
  // Using in a timer to raise the event on the main thread
  
  RaiseEvent ThreadFinished
End Sub

Private Sub UIUpdateTimerAction(t as timer)
  RaiseEvent UIUpdate
End Sub

Public Sub UpdateUI()
  UIUpdateTimer.Mode = Timer.ModeSingle
End Sub

So if you want to update the UI you just call UIUpdate wherever you have the thread implemented. This probably isn’t needed any longer since Xojo now gives you the ability to do this directly. So the only thing you probably need is the Finished event.

Like I say, really easy to implement. No plug-ins needed.

4 Likes

Wow Jon thats amazing, thank you for such a full and thorough explanation. I will be coding that up tonight!
Stay safe!
Mark

1 Like

You forgot to release the timer handlers. Otherwise it will leak (a lot) of memory.

1 Like

You know that is a very good point.

Thank you for pointing that out.

@Jon_Ogden - thanks for such a clear example. I had a semi-working version from @Norman_Palardy but this is a more elaborate version. Thanks again.

I have an example project here:

ThreadWithFinishedEvent example

3 Likes

@Jon_Ogden
Thank you so much Jon. Perfect!
Got it working great now.

1 Like