Custom ProgressBar timing issues

I’ve updated it to draw the countdown in the progress bar:

Oh, drawing it is not the problem. That works perfect. It’s just the overall time is off because Xojo’s timers aren’t clock accurate.

As said several times by others, this is NOT how timers are intended to work. :neutral_face:

You use a smaller period and use code to update labels, counters and progress bars when needed

That’s how the SHOULD work. There is zero downside to making the timer clock accurate.

Maybe you are unable to think of any downside but maybe the thousands of experienced engineers that designed the timers like that in the OSes thought of many.

Anyway, that is how they ACTUALLY work. If you want to have the intended outcome, you have to change your code to use timers as intended.

Also, you can buy some 3rd party plugins to use the OS High-Resolution Timers, they are a little more precise but have some of those downsides.

It can’t be, in a modern application you can’t even guarantee that your application will be running on the CPU when you want the timer to operate. Another application could be working at that point and preventing yours from working.

Run the timer at the smallest interval and then calculate the time required, percent complete and update both as required.

Kevin,

I was able to incorporate your logic into my project. It took sometime, as I had to replace your numbers with my countdown clock format among other things…but it works!!! Both the progress bar and the countdown clock are “clock accurate” now and finish together.

Thank you very, very much! This is what I needed, a code example from which to extrapolate from.

Two minor tweaks I’d like to ask about.

  1. This progress bar is “choppier” than the one I was using. Is there a way to make it smoother? Perhaps two half segments per second?

  2. The progress bar comes up just a click short of the end of the border when it finishes. I’ve tried adjusting this, but haven’t seemed to figure this one out.

Thanks again!!!

Of course it can, using the System Ticks method that everyone here is mentioning. The programmer shouldn’t have to code it, it should just work that way to begin with.

Even if that was true (and I’m skeptical) there’s no reason why it can’t be an option. Either a check box in the IDE and or setting. Something like

ClockAccurate=True

Not in a multitasking operating system. You cannot guarantee to be the running application when the timer happens.

1 Like

Well, as I said, the timer should have the option to be clock accurate by using System.Ticks. This feature could be programmed into the Timer itself by Xojo’s engineering staff, and activated by a setting such as

ClockAccurate=True

Unless of course, you believe System.Ticks is also not accurate on a multitasking operating system. In which nothing matters, and we should go back to using abacuses.

No, I am saying that when the timer reaches its time, your application may not be active on the CPU. There is nothing your application can do about that if the OS isn’t giving you a time slice at the time your timer expires.

If you say that the OS should take account of that and ensure your application needs its timer to operate, what if two applications required it at the same time. What if it is 50, sooner or later it is not going to be possible to honour every timer request.

That really isn’t possible, as everyone is trying to tell you. The way to smooth out your progress bar is to shorten the timer period so it fires more often and then do the math to tell it when to update the bar and clock.

I’m going to pigeon whole the Timer argument for the moment.

Shortening the Timer period has no effect of the choppiness of the progress bar, even down to 1.

Hopefully Kevin will chime in, as this is more or less his code I’m using.

New version here which should draw the bar much smoother:

That looks amazing!

I used this code in my project and made all adjustments to my code (exactly like last time). Everything looks good (progress bar much smoother) except that the numbers on the progress bar flash back and forth between my CountDown Clock format (01:30) and the straight integers you were using (90). I’ve changed all your label1.text to a string I’m using just like I did yesterday with your code in mine. But unlike yesterday, I get this flashing back and forth. It’s almost comical…I can’t find where in the world your code is displaying the integer, especially since the whole label1.text control is gone. I know it must have something to do with the changes you made to make the progress bar smoother, but I can’t find where the integer is still being displayed, and why only for a half of second.

Here’s my Paint Window

g.ForeColor = RGB(14,215,229)
g.FillRect(0, 0, self.mBarWidth_, g.Height)


g.ForeColor = rgb(0,0,0)
g.Bold = true
g.TextUnit = FontUnits.Point
g.TextSize = 16
g.Drawstring (PrePaintClock, Max(Floor(Self.mBarWidth_ -8) - g.StringWidth(PrePaintClock), -50), ((g.Height - g.TextHeight) / 2) + g.TextAscent)

Here’s my Update Method

dim mins, secs as integer

countdowntime = MessageTime - self.mRunTime_

self.countdowntime = self.countdowntime - 1
mins = self.countdowntime \ 60
secs = self.countdowntime mod 60
PrePaintClock= str(mins, "00") + ":" + str(secs, "00") 



Dim updateProgressBar As Boolean
Dim newBarWidth As Double

updateProgressBar = False

'calculate the new bar width and flag that we need to update it if the width as changed
'note. we round the width to half pixels to make the the progress bar more smooth
newBarWidth = Self.mPixelsPerSecond_ * ((Ticks - Self.mStartTicks_) / 60)
newBarWidth = Round(newBarWidth * 2) / 2
newBarWidth = Min(newBarWidth, Self.mMaxBarWidth_)

If newBarWidth > Self.mBarWidth_ Then
  Self.mBarWidth_ = newBarWidth
  
  updateProgressBar = True
  
  System.DebugLog Str(newBarWidth)
End If


'if the runtime has changed since last time we need to update the progress bar
If Self.mLastCountDownUpdate_ <> Self.mRunTime_ Then
  Self.mLastCountDownUpdate_ = Self.mRunTime_
  
  PrePaintClock = Str(MessageTime - Self.mRunTime_)
  
  updateProgressBar = True
End If


'update the progress bar
If updateProgressBar = True Then
  PROGRESS_CANVAS.Refresh(False)
End If

Timers are a feature of the OS :roll_eyes:

To execute code every single cpu cicle and have a core ussage of 100%, increasing thermals and power consumption while reducing app responsiveness :rofl: :rofl: :rofl:

And even then, as Ian said, there is no guarantee that the app is going to be “free” to receive the event in the exact Tick, so by the time the app can receive the event, it will not be accurate anyway.

I would like to thank Kevin for all of the help he gave me. Ultimately, I had issues with that method that didn’t work. I’m sure it had nothing to do with Kevin’s logic, just me trying to implement it into my project.

So started over with my two timers for the countdown clock and the progress bar. I then learned how to use SystemTicks (as Tim and others suggested) to do corrections, then added a third timer with this logic to correct the other two. Once I was happy with the results for that three timer method, I was able to consolidate everything into one timer.

Thank you to everyone who chimed in. All is well.

I’m mystified why you would need more than one timer.