Custom canvas progress bar not updating on 64 bit

I have a custom progress bar class that I use on several windows and have multiple custom classes and windows methods that update it during loops and it all works fine on 32 bit but so far on Mac 64 bit (haven’t tested on Windows) the update does not work.

I have tried Refresh, Invalidate and UpdateNow and also putting a timer on the window to refresh it and that also doesn’t work.

After trawling through the forum it seems that the only way may be by using the Task (thread class) that calls UpdateUI etc but while this is fine when calling an instance of the thread on a window for one particular task, how do I get this to work for custom classes that have multiple methods that need to update the progress bar on their parent window?

Is there a way to run code in a method in a thread within the class itself?

Confused. Hope someone can point me in the right direction.

The classic way consists in putting any loops in a thread, and update the progress bar from a timer.

All that can be done within a class.

Your normal code runs in the same thread as the UI so most of the time it will not be able to update any UI such as a ProgressBar while it is running. I’m a bit surprised it worked in 32-bit, but event handling differs slightly between architecture and even OS’s so maybe you got lucky.

The solution is to do as Michel suggests: put the code in a Thread and use a Timer to read a common property that is used to determine how to update the ProgressBar.

There are several examples of this included with Xojo.

More information here:
https://documentation.xojo.com/topics/threading/running_code_in_a_thread.html#Communicating_with_the_User_Interface

Thanks, Paul.

The problem is I have about 80 methods spread across my large project on multiple windows using multiple module and classes that need to update different progress bars (same progresssbar class), and each of these methods have multiple parameters and sometimes need to return values also.

I have searched the forum and it seems my only option may be to create separate threads (or task threads) on the fly and use WeakAddressOf handlers at the top of each of these methods and create the new handler method in the same module or class BUT how on earth am I going to pass all the various parameters that are different for each method or even use return values?

It seems like an awfully complex task and would create a lot more “hack” code to get it working and maybe I would have to create a custom thread class literally for each of the methods I need to use it in just so I can pass the parameters I need. I don’t mind hard work but not when it muddies the waters of my code structure and makes it even more confusing to navigate.

Are there any other ideas on how to achieve this without pursuing this soul-destroying code muddling route?

Without seeing your code it’s impossible to say what causes your problem. What I can say is that your progress bar should be decoupled from the calling code.

If you take a look at the Task version of updating UI from a thread, you can make that the new superclass for all of your threads and be done relatively quickly. However, if your progress / UI updating functions have return values, you’ve probably got a lot more design work to do. You will need to decouple all UI from business logic.

Thanks, Tim. Yes, I understand that in theory but it still means making a thread for each method in order to handle all the different specific parameters which seems real messy. And as you say, decoupling the UI interactions and logic code is going to be nightmare.

I have tried a very basic test by just adding the task thread class instance to the window for a simple concatenation of a string in a tight loop (see code below) and whether I use my own custom canvas class progress bar or the Xojo control it does not update it unless I continuously move the mouse around during the execution… otherwise it starts off then when it’s finished it jumps to the end.

ProgressBar1.maximum = 100000
Task1.run

Sub Run() Handles Run
  Dim s as string
  
  For i as integer = 1 to 100000
    s = s + "hello"
    Me.UpdateUI("Update":True)
  Next
End Sub

Sub UpdateUI(args as Dictionary) Handles UpdateUI
ProgressBar1.Value = ProgressBar1.Value + 1
End Sub

Your tight loop should be in a thread. Otherwise it locks up the main thread.

It is in a thread as per my code above. Task1 is an instance of the example project thread class that allows the update of the UI.

The maximum value of maximum is 65536 going higher may cause issues. As you have ProgressBar1.maximum = 100000
It may give a spinning wheel, and seems as if the ui is locked up.

Perhaps you may wanna try to set the maximum to 100 and show a percentage which may be more efficient and requests less updates to the UI

How do you know what data type is he unisng in HIS Custom Canvas Progress Bar?

That souns like you are not redrawing the custom canvas in the right place, just put a timer to fire the update.

That is the problem, you created the code in a way that xojo is not made for. Maybe something like the Observer Design Patterns could help

[quote=430411:@Derk Jochems]The maximum value of maximum is 65536 going higher may cause issues. As you have ProgressBar1.maximum = 100000
It may give a spinning wheel, and seems as if the ui is locked up.

Perhaps you may wanna try to set the maximum to 100 and show a percentage which may be more efficient and requests less updates to the UI[/quote]

I had used a percentage in my custom canvas progress bar but forgot to do that for the Xojo one. Both now work by always setting a maximum of 100 and only updating the control on each percent, not every iteration.

This is interesting. Thanks. I need to think about whether this interface/notification idea and updating the progress bar through it might work and whether it’s a practical solution. It seems pretty complex to get my head around at first glance.

Now I know for sure the custom thread/timer class works at least it’s a potential solution but I still can’t figure out a clean way of executing about 60 different methods in different modules and classes with varying parameters without creating 60 different custom threads with their own parameters etc.

If there was a way to create a super class (one ring to rule them all) that could be helpful but the varying parameters and occasional return values makes this harder.

Unless, as you say I can do it through a class interface which I am unfamiliar with.

You need to abstract your progress. Your different methods all need to do the same thing.

  1. They need to say “I want a progress”.
  2. Then they say “update the progress”.
  3. And finally they say “progress: go away”.

It’s now the responsibility of the progress to show up and to update the progress. Observer pattern is one way to do this. Or an interface. I use notifications.

If you think that Observer pattern is complex then have a look at https://www.amazon.com/Head-First-Design-Patterns-Brain-Friendly/dp/0596007124 . The age of the book doesn’t matter because it teaches principles.

I usually set Maximum to the width of the progressbar, multiply the percent by that and only update when the pixel count changes. That gives you pixel-level updates to your progressbar.

[quote=430437:@Beatrix Willius]You need to abstract your progress. Your different methods all need to do the same thing.

  1. They need to say “I want a progress”.
  2. Then they say “update the progress”.
  3. And finally they say “progress: go away”.

It’s now the responsibility of the progress to show up and to update the progress. Observer pattern is one way to do this. Or an interface. I use notifications.

If you think that Observer pattern is complex then have a look at https://www.amazon.com/Head-First-Design-Patterns-Brain-Friendly/dp/0596007124 . The age of the book doesn’t matter because it teaches principles.[/quote]
Thanks, I may need to look into this.

Thanks. Yes, my progress calculations and drawing are not the issue now, it works fine, it’s how to show it with a screen update and threads.

dim t as new Task AddHandler t.Run, AddressOf thread_Run_OpenFile AddHandler t.UpdateUI, AddressOf thread_UpdateUI_OpenFile t.run

I’m experimenting replacing my existing OpenFile() method with creating an instance of the task thread class but am having problems. The code above replaces the original OpenFile code which has now been moved to thread_UpdateUI_OpenFile() method instead with sender As task, args As dictionary parameters. When the run method is called it is raised correctly and then calls sender.UpdateUI(“Update”:True)… but the UpdateUI event never raises and the thread_UpdateUI_OpenFile never fires.

I’ve tried to debug the Task at each stage of its execution and the Run event clearly occurs and the sender.UpdateUI(“Update”:True) occurs but thread_UpdateUI_OpenFile does not.

I can manage it if there’s an actual instance of the class on the window but not if created on the fly.

Also, how can you access a listbox’s property such as ListCount and AddRow in a thread to fill it in a loop using the thread/task class?

I can see how to do the whole thing in a task outside of the thread but if you do that then the update progress bar call would be part of the same loop task and so still wouldn’t show because the entire loop is outside the thread.

I guess I need to be able to do the whole loop in the thread but just create a task to add row and task to update progress bar etc and then when the loop finishes continue the thread and move onto the next item of code.

[code]
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[/code]

On a totally different tangent, I find that updating a progress bar too many times slows the process down immensely. So I only update it every nth time through the loop, and its much faster and smoother. Like this pseudocode:

While not something.EOF do some processing x=x+1 if x mod 1000 = 0 then UpdateScrollBars() Wend

You might give it a try. It might help your situation. Fiddle with the mod value according to your needs.

[quote=430552:@Richard Nicolella]On a totally different tangent, I find that updating a progress bar too many times slows the process down immensely. So I only update it every nth time through the loop, and its much faster and smoother. Like this pseudocode:

While not something.EOF do some processing x=x+1 if x mod 1000 = 0 then UpdateScrollBars() Wend

You might give it a try. It might help your situation. Fiddle with the mod value according to your needs.[/quote]
I’ve found it more easier and more efficient to have the progress UI update via a timer (maybe 2 or 3 times a second). The timer would read some properties (which were set in the thread’s loop) and then decide if the progress UI needs updating (ie: update only if the values have changed).
This removes the responsibility of updatijg the UI away from your threads and also avoids you having to fiddle with the update rate in your loops.

[quote=430552:@Richard Nicolella]On a totally different tangent, I find that updating a progress bar too many times slows the process down immensely. So I only update it every nth time through the loop, and its much faster and smoother. Like this pseudocode:

While not something.EOF do some processing x=x+1 if x mod 1000 = 0 then UpdateScrollBars() Wend

You might give it a try. It might help your situation. Fiddle with the mod value according to your needs.[/quote]
Thanks but I do this already.

[quote=430569:@Kevin Gale]I’ve found it more easier and more efficient to have the progress UI update via a timer (maybe 2 or 3 times a second). The timer would read some properties (which were set in the thread’s loop) and then decide if the progress UI needs updating (ie: update only if the values have changed).
This removes the responsibility of updatijg the UI away from your threads and also avoids you having to fiddle with the update rate in your loops.[/quote]
Thanks and yes polling is something I’m considering but in the end the progress bar is now not really the issue.

The issue is moving the code to a thread (to allow a progress bar update however I achieve it) and updating and accessing the other UI elements within it hence the example code above.

I’m focusing initially on my OpenFile method that reads file data and then populates multiple controls on screen and to have all this in a thread is difficult so I need to work out a logical and practical way of doing so. And even if I store the data to a listbox style data structure first that doesn’t take long, it’s the actual filling of the listbox that would be time consuming (even if filtered to what you only need to see) and catches you out with UI Accessing Thread exception etc.

I’m gonna post the code issue example again to clarify the problem:

[code]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[/code]

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.