Custom canvas progress bar not updating on 64 bit

[quote=430589:@Thomas Eckert]No need to create Timer at all. I call just

Xojo.Core.Timer.CallLater(1, AddressOf updateProgress, progressValue)

in a thread. This is called as soon as the main thread can do it and it does not hurt the program structure.
“updateProgress(progressValue as Auto)” is a Window method.[/quote]
Yes I understand this. The problem is handling things like the listbox fill and accessing control properties from the thread and using these values for the next section of code in a thread etc as per my code example.

[quote=430583:@Denise Adams]Thread.Run

// This would cause ThreadAccessingUI error
Listbox1.DeleteAlRows

For i As Integer = 0 to count
// Parse data for row
// Create timer task to AddRow and somehow pass data parameters
// Create timer task to update progress bar
Next

// This would cause ThreadAccessingUI error but we need to access it for next section of code
Dim myListboxCount As Integer = Listbox1.count

// Do something with that value
[/quote]

I get what you want. You want the thread to stop, then setup a one-shot timer to update the user interface, which then resumes the thread. This is indeed possible. Cannot hick up code, while we have created a plugin class " ThreadSafeGUIProcessor" of the Scripts plugin, or the " ThreadedTimer" in that same plugin. I think you can accomplish this in pure Xojo code, and you could try to use one of those plugin classes, and go from there to produce your own code. If you need further help, then first download the scripts plugin , try them out and we go from there.

Thanks Alfred. Yes, I think you understand my issue here.

I would initially like to do this in pure Xojo code if possible. So let’s say I manage to fill the listbox up in the thread by calling the UpdateUI method for each add row but then after the fill loop is complete I need to access the listcount value of the now filled listbox before continuing with the next code execution in the thread… how would I pause the thread to know when the listbox is filled so I can resume it to get its listcount?

And would I have to pass a “ListBoxFillComplete” boolean parameter to the last “AddRow” call of the UpdateUI method so that it can then somehow return this value to the paused thread so it can resume? But how to return it to the thread and resume it again without running a While/Wend loop in the thread polling some kind “FillingListbox” global boolean etc?

I don’t think this is necessarily a Xojo problem but a change in how Apple is servicing the event loop. It now just marks things as needing to be redrawn and will not, under any circumstances even touch the screen until your code returns control back to the loop. Well thats too strong, but all of the old ways to make something update now are completely broken in 64 bit builds.

There is a sort of kind of work around that everyone here will probably ban me from ever posting again to mention, but if you call app.doEvents() the screen will update while you’re looping.

Depending on your usage this could cause other huge and difficult to debug problems as those can stack up and it won’t service the first one until the second is finished and so forth. I used this for a time as a work around as I slowly updated a huge amount of code that tried to use the various methods to force an update that no longer work. I slowly removed the parts one after another until the entire code is free from it again now, but it allowed me to keep going rather than take a month off to re-write everything.

It really could cause other pain, but it’s worth experimenting with in the short term while you continue to work to get rid of it.

I think you need to completely separate data processing and access to the UI.

Idea.

  1. You have a class that holds the properties for one row.
  2. You have an array property of the class that can be accessed by both the thread and UI.
  3. The thread generates the data and appends it to the property array.
  4. A timer keeps the UI (listbox / progress bar) in sync with the array property.

This has the benefit that all of your thread actions will be safe as they will never touch the UI.

If you perform any actions on the data afterwards (for example, CRUD), you would perform them on the data held in the property and update the UI afterwards.

[quote=430652:@James Sentman]I don’t think this is necessarily a Xojo problem but a change in how Apple is servicing the event loop. It now just marks things as needing to be redrawn and will not, under any circumstances even touch the screen until your code returns control back to the loop. Well thats too strong, but all of the old ways to make something update now are completely broken in 64 bit builds.

There is a sort of kind of work around that everyone here will probably ban me from ever posting again to mention, but if you call app.doEvents() the screen will update while you’re looping.

Depending on your usage this could cause other huge and difficult to debug problems as those can stack up and it won’t service the first one until the second is finished and so forth. I used this for a time as a work around as I slowly updated a huge amount of code that tried to use the various methods to force an update that no longer work. I slowly removed the parts one after another until the entire code is free from it again now, but it allowed me to keep going rather than take a month off to re-write everything.

It really could cause other pain, but it’s worth experimenting with in the short term while you continue to work to get rid of it.[/quote]
Thanks, James but I would like to steer clear of app.doEvents() because as you say many posts have stated its negative issues and I’d rather not cause other problems while trying to fix this one.

[quote=430653:@Kevin Gale]I think you need to completely separate data processing and access to the UI.

Idea.

  1. You have a class that holds the properties for one row.
  2. You have an array property of the class that can be accessed by both the thread and UI.
  3. The thread generates the data and appends it to the property array.
  4. A timer keeps the UI (listbox / progress bar) in sync with the array property.

This has the benefit that all of your thread actions will be safe as they will never touch the UI.

If you perform any actions on the data afterwards (for example, CRUD), you would perform them on the data held in the property and update the UI afterwards.[/quote]
Thanks, Kevin. Yes, at some point in the future I intend to create a data structure to store my data and then only display it to the user in a listbox when needed but right now this is not feasible unfortunately so I must find a way to somehow pause the thread and then return to it when the main thread has caught up. Passing data back to the thread is also proving difficult.

You’ve got to abandon this idea. It is not possible to fill the listbox in a tread. That’s what all the responses of the participants here were about. As long as you stick to your current thinking, you won’t be able to accomplish what you want.

Follow Kevin’s advice, and don’t say I will do it in the future ;-). To manipulate the thread, you can create a semaphore within the thread to signal ownership that would stop the thread. before you call signal you spawn a 1 shot timer. The timer should be a property of the thread instance. Once the timer runs, after signal (the timer fires then), you call semaphore release in the timer event.

Another way is to call thread.suspend, but that, if I remember correctly, cannot be called within the thread. You’ll thread.resume in the timer.

These are the approaches for “synchronous” threading in conjunction with the main thread. “Asynchronous” threading can be obtained from some Xojo sample projects.

The bottom line is to create property holders being filled within the running thread, pass them on to the gui-properties in the timer, and you should be fine.

I repeat: forget your idea that you literally can fill a listbox in a thread.

Yes I understand. What I meant by “let’s say I manage to fill the listbox up in the thread” was that I do the loop in the thread but pass the AddRow action to the update UI timer… and actually this now seems to be working.

I’m not sure how to use Semaphore but I have managed to use sender.suspend from within the thread handler method itself and I’ve started a polling timer from before calling thread.run which polls the thread and when it sees that the thread is suspended and all the UI events have been dispatched it calls thread.resume and that works. I can then also use the polling timer to update a progress bar in the main thread.

I’d like to know how semaphore works but I guess if I can call suspend from within the thread itself maybe that’s not necessary.

I think I have a grasp of it now and maybe can use the suspend/resume method to pause the code in order to get a final listcount value etc before continuing the code to use that value by either setting that value to a global property or creating a mListCount value on my listbox subclass (after every AddRow, InsertRow etc etc) and accessing that instead.

Well I thought I’d post an update. Turns out that most of the time taken on load file is all the UI updates so any solution I try, be it an HTML viewer with CSS progress, intermediate progress bar, custom canvas progress bar and timer etc etc does not animate anything while all the other UI updates are being processed. If the main code was thread-based it would work fine but not with all the other UI updates.

So, I’ve unfortunately reached an impass. I have about 3-5 seconds of UI updates (my app has a very complicated interface) and no way of communicating to the user that something is happening other than the spinning ball on macOS and nothing at all on Windows. I can set a status message on screen at the start of a process but since it doesn’t animate it doesn’t really draw the user’s attention.

I wish Xojo had a way to create its own thread for animations that could run simultaneously with the main thread and have some kind of priority over it intermittently to do a minor update but alas it does not and normal threads are useless because a) you can’t update the UI immediately in a thread and b) sometimes the lag is down to other UI updates and not number crunching.

If anyone has any great ideas I’m all ears…

Let’s make sure what this means, based on your previous posts:

  1. “load file” means that the file is loaded in the thread, I guess
  2. “UI updates” means update in the main thread.
  3. “time taken” means the loading of the file conform to point 1

Furthermore, [quote=431249:@Denise Adams]while all the other UI updates are being processed[/quote]

  1. UI updates are being processed means that the numbers produced in the thread cause the spinning ball, not the UI updates.

But before I would continue (a polling timer aka a continuous timer defies the purpose of “synchronicity” of the thread with the main thread), I’d rather want to know if this “semantic analysis of your ambiguous wording” is in essence correct.

I’ll try to be as clear as possible and bullet list order of events:

  1. Select “Load File” which then calls LoadThread.Run which is a Task/Thread based on the Xojo example project.
  2. LoadThread opens the file (which takes minimal time) executes loading operations and every time it encounters an interaction with the UI it calls "UpdateUI(“ClearListbox”:Listbox1) etc but that is just an example. I even have the fill listbox loop in the main thread but do the UpdateUI call to “AddRow” or Canvas.DrawPic etc.
  3. As the main thread continues to execute code the UpdateUI queue builds in size (is appended to) and executes each task to update the UI.
  4. When the main thread has reached its end it adds a final UpdateUI call to signal the code has completed.
  5. When the final UpdateUI event in the queue is found and processed it sets a global flag notifying the app that the load is complete and allows user-interaction with the interface again (so it did not interfere during the load process) and displays System.DebugLog of the total time the entire thread and UI updates took.

Points to note:

  1. The actual main thread processing time is way under a second. The total time can be anywhere between 2-5 seconds.
  2. Some of the UpdateUI calls have other code in them that does not touch the UI but they call various methods within methods that are used many other times throught the app, buried deep, and cannot be disentangled easily so I keep them with the UI updates. That said, I have looked at the code and it is less complex than the load file code so I doubt even if I extractated it all out and separated them into number crunching code and update UI code it would have any real impact.
  3. The reason the UI locks up and a ball spins or it freezes during load (depending on OS) is because of all the UI updates, not the number crunching code, and some updates have to happen in a certain order for other updates and code to work correctly, it would not work correctly if everything was asynchronous.
  4. I have tested with timer, Xojo.Core.Timer, TimerMBS, HTMLViewer progress bar in CSS and they all freeze as soon as any other UI updates have to be processed. If code is running in a thread or no UI updates they work but unfortunately any form of timer polling the main thread or LoadFIle thread will not work. Even Xojo’s own intmediate progress bars stop animating.

Your UI must be mighty complex to trigger the beachball when updating.

It is. Multi-tabbed views with hardly any standard controls. Mostly custom canvases and all listboxes are custom subclasses that render row pics in the paint event and have canvas scrollbars.

Ugh!

The UI locks up is not true. The thread locks up the UI.

You have to use a single shot timer every time you suspend the thread. The single shot timer gets the non-UI properties from the thread and assigns them to the UI properties. Then you should retrieve the updated UI properties during this one time firing of the timer and assign the new ui props to the thread props and call thread.resume.

Your thread does another crunch based on the new updated thread props, you set up the one shot timer again, call thread.suspend.

That is the true cycle of a thread->mainThread->thread->mainThread.

Did you see my private message?
I can’t find it either now … I’ll send again.

[quote=431310:@Alfred Van Hoek]Ugh!

The UI locks up is not true. The thread locks up the UI.

You have to use a single shot timer every time you suspend the thread. The single shot timer gets the non-UI properties from the thread and assigns them to the UI properties. Then you should retrieve the updated UI properties during this one time firing of the timer and assign the new ui props to the thread props and call thread.resume.

Your thread does another crunch based on the new updated thread props, you set up the one shot timer again, call thread.suspend.

That is the true cycle of a thread->mainThread->thread->mainThread.[/quote]

Thanks, Alfred. Yes, I did indeed find away to suspend a thread, calculate a value and return it to the thread which then resumes but my main problem right now, irrespective of using the main thread or a thread and timer is finding a way to smoothly animate an intermediate progress bar while all the UI updates are being processed in the main thread.

A progress timer simply does not fire while all the other UI updates are being processed and pausing all the UI updates to allow the timer to update the progress bar just slows down the entire operation and is counterproductive.

And for completeness you could try the projects “ThreadedTimer”, “ThreadInterupt” and the “MultipleInterupt” projects that come with the Scripts Plugin that I mentioned earlier. It contains the ThreadedTimer class, which services your thread and the main thread.

I think that the more complicated project shows how you can setup multiple interrupt threads.

I don’t see ThreadedTimer or the others in the Scripts Plugin Xojo Demo.zip . Am I downloading the wrong thing?

Denise,

thanks for the heads up. It appears I never uploaded version 3.1. Will do so in a short moment. Will announce it ASAP. Scripts Plugin