Understanding Threads?

Hey guys,

I have a large loop (with inner loop) that effectively stops the UI from responding until the loop processing is complete.

Part of the behavior of the loop(s) is to add rows to a list box. The list box currently doesn’t get updated until the end of the loop. :frowning:

So, from what (little) I’ve read, it appears that I need to implement thread(s) so that I can yield or sleep or ??? so that my list boxes can update?

Is there any documentation/videos on the subject of threads that a newbie could understand? I’ve tried things like: App.SleepCurrentThread(), etc. but I really have no idea what I’m doing?

Any help on the subject would be greatly appreciated.

Thanks, Ken.

Hi Ken. I actually just got my first thread working. I needed it for a similar operation of pulling data from a MySQL table and populating a SQLite table. Previously, I did this without the thread, and while the operation completed in several seconds, the app went unresponsive until it finished. The thread works much better in that it doesn’t hold up the app with the rolling beachball. I use a progress bar too to show the user that the operation is still processing.

I found there are 2 examples in Xojo that you should check out too. If memory serves me, they’re in Desktop > Controls > Threads. There is one with the use of a timer and the other that goes by processes. The non-timer one is the one I based my project off of since it was more appropriate

If no one else beats me to it, I’ll post back tomorrow morning some snippets of my code with explanations on how they work.

Of note, using a thread will actually slow the process down a tad. I think this was mentioned in the docs. Without the thread (unresponsive app), I was able to move a couple thousand records from MySQL to the local SQLite table in a bit less than 10 seconds. With the thread, the process takes around 15-20 seconds, but I feel the use of a progress bar and the non-unresponsive app is a better experience

1 Like

Many thanks Ryan, I did find one example project but (to be honest) it was a little over my head.

I’d really appreciate seeing some simple sample code that allows me to use my loop to pull data from my spreadsheet data source and (conditionally) write some of it to my list box being able to see each record as it gets added to the list box row.

I’ll keen to see what ever code snippets you are prepared to share with me.

Many thanks mate!

Ken.

In your loop, you reach a point where you have (say) a string that you want to put into a listbox cell. Instead of doing that, you will be sending that data (row, column, string) off to be separately added to the listbox.

Yiou want to make a subclass of Thread, and you could add a method to it:

UIupdate (arg1 As variant, arg2 As Variant, arg3 As Variant)
// Stores the requested UI update and sends it off for actioning.

Var  UIdict As new Dictionary

UIdict.Value("row")   = arg1
UIdict.Value("col")   = arg2
UIdict.Value("str")   = arg3

me.AddUserInterfaceUpdate (UIdict)

Start your thread thus:

myThread = new mythreadClass ()
AddHandler myThread.UserInterfaceUpdate,  WeakAddressOf app.updateUI      // Wire in the UI updater function for this thread
Addhandler myThread.run,                  AddressOf     mythreadcode      // Wire in the main function for this thread
myThread.Start ()                                                         // Everything ready, can run the thread now

// Thread goes off and starts doing your loops.

Then in your thread, when you need to add an update to a cell, you do:

me.UIupdate (row, column, string)

Now, where is the actual updating work done? Well, add the mthod to do it - you’ve already seen it referred to as updateUI() which got wired in above as the event handler for user interface updates. This could look like:

updateUI (t As mythreadClass, UIdata() As Dictionary)

Var  updateItem as new Dictionary, row, col as integer

while  (UIdata.LastRowIndex>-1)
  
  updateItem = UIdata(0)
  UIdata.RemoveRowAt (0)
  
  row = updateItem .value("row")
  col = updateItem.value("col")
  mylistbox.cellValueAt(row, col) = updateItem.value("str")

wend

That’s the outline, showing the overall structure. I’ve not handled adding the row to the listbox, you may wish to add a flag to the list of args to tell the uiupdater to do that, or perhaps extend the argument list to pass all the row/col data at once.

The business with the while loop in the updater handles the case where you’ve added several items to the dictionary array before the updater had a chance to take them off. It will then handle all the queued requests at once.

Note also that you have to add the new listbox row to the listbox in the updater - you can’t do that in the thread. Also, make the updater be a method of the application. That way the thread finds it more easily. And some variables such as the listbox will need to be global or at least with a wide enough scope that they can be referenced.

2 Likes

The User Guide Threading topic has links to a video and a variety of sample projects so it might be helpful.

In general you’ll want to move your long-running process to a Thread and then do the UI updates in either a Timer (that checks the Thread for data to add to the UI) or by using the Thread.UserInterfaceUpdate event.

1 Like

You can also look at my Looper class.

Drag it into the window, implement the events, and you can update your Listbox while leaving the UI responsive.

2 Likes

Wow, just Wow! Thread.UserInterfaceUpdate - I really need a better internal process to check what has been added in a particular release … I have never realized this addition. Priceless!

1 Like

Well, everyone beat me to it! In any event, I made up a quick sample project for you with comments along the way. Hope this helps!

Of note, I am not known for being the “best practices” Xojo guy, so I’m sure if anyone else sees this, they’ll probably be shaking their head :sweat_smile:

1 Like

Some of the more recent documentation is pretty weak in my opinion - the new Web 2 stuff in particular.

1 Like

OMG! … you guys are the BEST. I love this forum.

HUGE Thank you to ALL who contributed to my Xojo addiction. I feel like once I have a handle on threads and background processing, I can go back and retro-fit my other (older) projects.

You guys are the best!!

Sincere thanks, Ken.

4 Likes

lol, yeh seems you gotta be quick here.

Many thanks for the sample project mate, I’ll be dissecting it like a kid opening a XMas pressie!!

Thanks for your help. :wink:

Thanks Paul, I did look for documentation, but clearly I did a poor job.

Now, I just need a coffee and a few minutes to sit back and try to absorb the instructions.

Thanks mate.

1 Like

Thanks Kem,

I really appreciate you sharing your code with me. I’ll be sure to give it a go!

Ken.

Tim, Thanks for going to so much effort to lay this out for me!

Can’t wait to try to implement my own.

Many, many thanks.

Well I hope it helps, Ken. One other thing I discovered: my threads mostly do I/O and not really any heavy processing. But they do quite a bit of fiddling with the user interface and putting status messages out to the user via a status bar at the bottom of the main window. This includes a ‘sign-off’ message when the thread ternminates. Initially, I wasn’t seeing this final message, but then I realised that what most likely happened is that the thread terminated before the final event could fire. So I just added a one-second sleep at the end of each thread. That allows the UI change to be done.

1 Like

yes, but as far as I remember that was always the issue and will be corrected over time. But since I’m using Xojo I’ve been struggling with news additions. It is human that you concentrate (aka read) those which you need first in the particular projects you are just working on. It is pretty hard to keep all changes in mind. Unless I’m reading it here or code from others (for instance through the Feedback App) you normally don’t bump into the new stuff, as you don’t know what you have to search for …

Oh I agree. Part of the understanding is being aware of the changes in the first place.

1 Like

What often helps is reading the posts from “beginners”. When you think what the heck are they trying to do here, that’s a good indicator that I missed something in the past 15 years :slight_smile:

1 Like

I always read through the Release Notes to see if there’s anything that relates to something I had a problem with, somthing where I had to find a workaround. This new event for UI work from threads is a case in point, also the ability to do stuff with listbox headers and the new communication methods into and out of HTMLViewers all come to mind.

1 Like

Just wanted to let everyone (on this thread) know that, with all your help I now have a (somewhat tenuous) handle on threading and have it implemented in my current project.

Thank you all for your generous help.

Ken.

2 Likes