Show only relevant numbers from stopwatch - vb.net

While attempting to make a stopwatch, I noticed that it would display all groups of numbers related to the timer (in this case "00:00:00:00")
In order to show only relevant numbers, and not show the minutes column when a minute hadn't passed, I came up with this code:
Public Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
Dim sw As New Stopwatch
Dim elapsed As TimeSpan = Me.stopwatch.Elapsed
Label1.Text = String.Format("{0:00}:{1:00}",
Math.Floor(elapsed.Seconds),
elapsed.Milliseconds)
If Label1.Text = "60:999" Then
Label1.Text = String.Format("{0:00}:{1:00}:{2:00}",
Math.Floor(elapsed.Minutes),
elapsed.TotalSeconds, elapsed.TotalMilliseconds)
End If
End Sub
When this code is active, the timer will only show the seconds and milliseconds column until it hits a full minute, in which case it will just loop back to 0 seconds and repeat. I'm assuming that the timer just can't detect exactly when label1's text is exactly 60.999, but I'm not sure. What is my logic missing?

Timers are not guaranteed to fire exactly at their interval. I'm assuming your timer is set to go off every 1ms, however when you run your program you'll find it will probably by raised every 3-16ms with a lot of jitter, this is also not helped by the fact the WinForms Timer (which I assume you're using) goes through the Win32 window message pump, rather than its own dedicated (and real-time) thread.
Anyway, the fix is to not compare strings, instead compare the actual time values:
If elapsed.TotalSeconds < 60 Then
label1.Text = String.Format("{0:00}:{1:00}", Math.Floor(elapsed.Seconds), elapsed.Miliseconds)
Else
label1.Text = String.Format("{0:00}:{1:00}:{2:00}", Math.Floor(elapsed.TotalMinutes), Math.Floor(elapsed.Seconds), elapsed.Miliseconds)
End If
Note you shouldn't be displaying TotalSeconds if you're already displaying Minutes.

There's a few problems with your code:
You are declaring a new Stopwatch inside of the Tick event. This is unnecessary.
You're using string comparisons to do something that should be done with math. Your hunch is correct that the exact moment when the label's text is "60:999" is being missed by the timer.
Instead of comparing the label's text value, just look at how many milliseconds (or seconds) have elapsed!
Public Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
Dim elapsed As TimeSpan = Me.stopwatch.Elapsed
If elapsed.TotalSeconds >= 60 Then
Label1.Text = String.Format("{0:00}:{1:00}:{2:00}",
Math.Floor(elapsed.Minutes),
Math.Floor(elapsed.Seconds),
elapsed.Milliseconds)
Else
Label1.Text = String.Format("{0:00}:{1:00}",
Math.Floor(elapsed.Seconds),
elapsed.Milliseconds)
End If
End Sub

Related

VB.Net Countdown - Timer has delay

So I just created a Countdown which updates each timer tick but using a real countdown to compare the one I coded has a small delay. After 1 Minute its like 3 Seconds slower than a normal timer.
The weird thing is that it works fine if I set the Interval to something above 1000 = update each second.
But everything below 1000 has a delay and I want a timer with milliseconds, update each 0.1 secon = Interval 100.
Thats the code I have so far (It looks messy because it switches the color of the label once it reaches a certain amount of time left)
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
Label1.Text = "Time left" & count
If count >= 12 Then
If change = False Then
Label1.ForeColor = Color.Chartreuse
change = True
End If
Timer1.Interval = 2000
count = count - 2
ElseIf count <= 11.5 And count >= 7.5 Then
If playaudio = False Then
playaudio = True
Label1.ForeColor = Color.Yellow
End If
Timer1.Interval = 100
count = count - 0.1
ElseIf count <= 7.5 And count >= 0 Then
count = count - 0.1
If changes = False Then
Label1.ForeColor = Color.Red
changes = True
End If
ElseIf count <= 0 Then
Timer1.Stop()
Timer2.Enabled = True
Timer2.Start()
playaudio = False
changes = False
change = False
count = 100
End If
End Sub
Is there any ohter way that the timer doesnt delay?
I think it's because the actions you take are delaying the next timer.
One way to work around the problem would be to set the timer to something like 10ms. At each tick, you check if the previous refresh is older than the desired delay.
Or you can set the timer in another thread, which will not be affected by the execution time.
Forms timers are notoriously inaccurate. Use a stopwatch to measure time and the Timer to update the display.
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Stpw.Start()
Timer1.Start() 'I have it set to 100ms.
End Sub
Private CountDown As TimeSpan = TimeSpan.FromSeconds(10.0#)
Private Stpw As New Stopwatch
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
If Stpw.Elapsed >= CountDown Then
Timer1.Stop()
Stpw.Stop()
Label1.Text = "Blast Off"
Else
Dim ToGo As TimeSpan = CountDown - Stpw.Elapsed
Label1.Text = ToGo.ToString("hh\:mm\:ss\.f")
Select Case ToGo.TotalSeconds
End Select
End If
End Sub
End Class
Start with this and you'll see how it works. Your color coding can probably go in the Select.
Here's a bit of a restructuring of your code. It's like dbasnett's stopwatch, except it uses a class you're more likely to be familiar with, to introduce the concept that "instead of using a timer and measuring time passage by adding up (or taking away) every time it ticks (which is subject to cumulative errors), pick a moment in time and regularly calculate how far away it is":
'code that starts a minute countdown
'class level property noting the end time
Private _endDateTime as DateTime
'the end time is a minute away
_endDateTime = DateTime.UtcNow.AddMinutes(1)
'we only need one timer
timer1.Start()
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
Dim count = (_endDateTime - DateTime.UtcNow).TotalSeconds 'how far away is the end time?
Label1.Text = $"Time left {count:0.0}s"
If count <= 0 Then 'reset
Timer1.Stop()
Label1.ForeColor = Color.Chartreuse
playaudio = False
Else If count <= 7.5 Then
Label1.ForeColor = Color.Red
ElseIf count <= 11.5 Then
playaudio = True
Label1.ForeColor = Color.Yellow
End If
End Sub
There is a lot of redundancy that can be removed in your code; we'll use a single timer, it can tick on whatever interval you like; if there is a label that is counting down with 0.1 second precision then we should maybe make it tick every 50ms
If you swap your ifs around you won't need to make them a range; if you're measuring less than, put the test for the smallest number first. Mostly these ifs won't enter at all, then when there is less than 11.5 seconds to go, the last if will start activating etc..
Nothing happens if you set a label color to be the same as it already is so you don't need that complicated Boolean setup with change/changes to make sure you only set the color once
The crucial thing is we have a fixed end point in time and every time we tick we work out how far away that is. We could tick 1000 times a second or once every 10 seconds, it doesn't matter; the end time is the end time is the end time

display a message to a label in vb.net at specified times during the day

I would like to display a sentence in a text box at a 5 specific times during the day automatically. for example:
at 5:30 AM,
Textbox1.text = "breakfast"
at 7:30 AM
textbox1.text = "leave for school",
etc.
a timer can just start when the application is launched, although it needs to refer to the local time or some constant time as the program needs to output at the same time each day of the week without me having to change it manually.
The proper way to do it is something like this:
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'Set the interval at startup.
Timer1.Interval = CInt(GetNextNotificationTime().Subtract(Date.Now).TotalMilliseconds)
End Sub
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
'Set the interval at each notification.
Timer1.Interval = CInt(GetNextNotificationTime().Subtract(Date.Now).TotalMilliseconds)
'Not sure whether this is required when the Interval changes or not.
Timer1.Stop()
Timer1.Start()
'Do the work here.
End Sub
Private Function GetNextNotificationTime() As Date
'...
End Function
How you implement that GetNextNotificationTime method depends on how the notification times are stored. The Timer will then Tick only when a notification is due.
You can still do this with a Timer and you wouldn't have to do any math...
Every time the Timer raises a Tick event, you check the value of: System.DateTime.Today.Now.ToString("HH:mm"). If it is equal to your preset time, change the text in the TextBox

Dynamically updating a progress bar in VB

Hello I am a novice / mediocre VB programmer and I made a timer that simply need to update it self every second.
I started having doubts about weather or not it was working so I applied a msg box to my timers code it went off every second updating it self but the progress bar wont? why?
Dim power As PowerStatus = SystemInformation.PowerStatus
Dim percent As Single = power.BatteryLifePercent
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer.Tick
ProgressBar1.Value = percent * 100
Label1.Text = percent * 100
End Sub
I have a power status and percent that takes the status and turn into a usable percentage then the progress bar uses that percentage but isnt updating like the msgBOX does why?
Well, your timer is probably working well and all, but you don't show where/how you get the updated value of SystemInformation.PowerStatus.BatteryLifePercent.
Maybe you're doing this somewhere else in your code, but as it is posted, you're always displaying the same value, so of course the progressbar is never going to change.
From what I can see from your question, everything should be working ok but I cant see that you have added Timer1.Interval = 1000 however you may have but this with the designer and not the coding side, however nevertheless here is how I did this project so you could see my working example just so you can be sure, If you have any problems let me know and i will do my best to help you out :)
Public Class Form1
Dim Timer1 As New Timer
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Timer1.Enabled = True
Timer1.Interval = 1000
AddHandler Timer1.Tick, AddressOf Timer1_Tick
Timer1.Start()
End Sub
Private Sub Timer1_Tick()
Dim POWER As PowerStatus = SystemInformation.PowerStatus
Dim PERCENT As Single = POWER.BatteryLifePercent
Dim ONCHARGE As PowerStatus = SystemInformation.PowerStatus
ProgressBar1.Value = PERCENT * 100
Label1.Text = "Power Remaining: " & PERCENT * 100 & "%"
If ONCHARGE.PowerLineStatus = PowerLineStatus.Online Then
Label2.Text = "Currently: Charging"
Else
Label2.Text = "Currently: Not Charging"
End If
End Sub
End Class
I added a Progressbar and two labels to the form, one of which is the computer battery and another of which will tell the user if the cable is unplugged in or not, i know you didnt ask for the cable status but i added it just incase you needed it :)
Happy Coding

Making a clock which would start running from specific time

I'm trying to make a clock which would start running from a specific time - e.g. the user sets the time to be 17.35 and it runs from there. What would be the easiest way to do it? I tried setting the time with Timeserial but couldn't figure out how to add time to it so it didn't get me anywhere.
Ideas?
edit: The idea behind the program is to show the user a normal digital clock that has been sped up.
Add a Label and a Timer component in your form and set the starting date and time (the date won't be visible). So if you set 17:35:00 the time will start from that moment and be updated every second like a clock.
Public Class Form1
Dim startTime As DateTime
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
startTime = New DateTime(2014, 1, 1, 17, 35, 0) 'setting time at 17:35:00
Label1.Text = startTime.ToString("HH:mm:ss")
Timer1.Interval = 1000 '1 tick every second
Timer1.Start()
End Sub
Private Sub Timer1_Tick(sender As System.Object, e As System.EventArgs) Handles Timer1.Tick
startTime = startTime.AddSeconds(1)
Label1.Text = startTime.ToString("HH:mm:ss")
End Sub
End Class
Create a form with a timer on it. Set the timer to 1000ms and enable it.
Dim three variables hours, mins, secs. On the timer event, increment the secs. When secs = 60, set secs = 0 and increment the mins; ditto mins to hours, then display the hrs:mins:secs in a format of your choice. Add a button which allows the user to enter starting values for hrs, mins, secs.
Depending on what you mean by 'sped up' you could reduce the delay on the timer if you want it to run faster, as opposed to ahead of local time.

Timer minutes is always 30 seconds out

Goodday, I use the below code to start a timer .
Label2.Text = Difference1.TotalMinutes.ToString("N0")
But the minutes are always 30 seconds out. The label shows the time as 1 minute when only 30 seconds have elapsed and thereafter I'm always 30 seconds out.
How can I calibrate this?
Thanks
Rob
If you look at the definition for the TimeSpan.TotalMinutes property it states that it:
Gets the value of the current TimeSpan structure expressed in whole and fractional minutes.
Therefore when you use the ToString("N0") format you are telling it that you want no decimal places and since it is a numeric format it will round your value up. You should look at using the TimeSpan Custom Formats in particular in this case the %m Custom Format string. It should look something like this:
Label2.Text = Difference1.TotalMinutes.ToString("%m")
Code I used to test. Timer interval is set to 1000 and is enabled.
Public Class Form1
Dim startTime As DateTime = DateTime.Now
Private Sub Timer1_Tick(sender As System.Object, e As System.EventArgs) Handles Timer1.Tick
Label1.Text = (DateTime.Now - startTime).ToString("%m")
Label2.Text = (DateTime.Now - startTime).TotalSeconds.ToString("N0")
End Sub
End Class