I wanted to set a value of a ProgressBar in a Thread like this:
WinSDCard.MyProgressBarr.Value = 0
WinSDCard.MyProgressBarr.MaximumValue = 10
For i As Integer = 0 To 10
MyProgressBar.Value = MyProgressBar.Value + 1
So every 200ms MyProgressBar should be filled up a bit till 2 seconds are passed (then it’s full). The weird effect: While the Thread is running I don’t see the progress in the bar. As soon as the Thread has finished MyProgressBar is filled up. Invalidate() or Refresh() doesn’t solve the problem.
Why this effect and is there a possibility to use a Thread to fill up a ProgressBar?
Based on the documentation I have tried a Timer to fill up MyProgressBar and that worked out of the box. I would like to use a Thread because something is running in the background while the progress bar is filling up and if that that background task is not completed the Thread can react to it (after expected time + some additional seconds).
A thread cannot directly update the UI. This blog post has some suggestions:
Wow, thank you, that was exactly I was looking for and it solved my problem, thanks a lot!
Or even easier:
self.ProgressBar1.SetValueThreadSafeMBS(n) if you have MBS
It’s easy. It’s not good.
As mentioned in the article, you’re wasting time. If you have 1000 steps and the progressbar is only 300 pixels wide, you’re requesting a context switch, update, and then another context switch 700 more times than the progressbar can even display. Plus the thing about Windows animation, and the fact that as humans we can’t really perceive that kind of rapid change. A timer updating the value only 4 times per second would still feel instantaneous, and is a hell of a lot more resource friendly.
So yeah, it’s easier to write. But it’s a lazy shortcut. There’s a reason something like that was never introduced to Xojo directly: people would use it.
Why shouldn’t I be lazy? Of course, I use a timer AND check the pixels so that I don’t do so many context switches.
The MBS method also de-spaghettifies my code a bit.
You’re still doing all your work on the main thread, leaving your app mostly unresponsive. This also circumvents Xojo’s scheduler. As for why you shouldn’t, I feel like I’ve already explained that.
Why am I doing all my work on the main thread? Why is my app unresponsive? You may know about Xojo’s scheduler. We don’t know that.
I have a thread, which does most of the work. Then there is a window for the progress. Then once a second and if the progressbar needs to be moved a pixel I mostly use CallDelegateOnMainThreadMBS. The ThreadSafe methods are used only for changing the visibility and if the control is enabled.
Maybe I sound dense. But I want to know if what I’m doing is suboptimal or not.
No you’re right, I wasn’t thinking through my response correctly. I was arguing that a thread should be used, which wasn’t actually the point. I’d call what you’re doing acceptable.
I don’t see what’s wrong with this. You’re using a thread and it does something on the main thread once a second. Personally I’d use
AddUserInterfaceUpdate but that’s a detail.
Thanks for the clarification. There are always these situations where you find out that something is really suboptimal. Cough… been checking some html which I use for printing and the CSS was totally wrong.
When I suggested self.ProgressBar1.SetValueThreadSafeMBS I did not mean to call this at every iteration of course, for precisely the reasons you explain. Depending on the exec time of each iter, the length of the scale bar, and # iters, I test for j mod m in the loop and update the bar only periodically. So the only extra work being done on the main thread is a j mod m test, which I’m sure Xojo compiles down to an extremely efficient binary that would take only a few clock cycles.