This should be fairly straight forward but I cannot figure it out,
I have a button on a form with the default back colour of silver, when the button is pushed it turns red,
If the backcolor is red and it reaches a certain time of the day I want the backcolor to change to black. The code I have used is as follows
If CAButton.BackColor = Color.Red And DateTime.Now > #11:48:00# Then
CAButton.BackColor = Color.Black
However for some reason now, it doesnt matter what time it is, as soon as I push the button it automatically changes to black, theres obviously something missing from the code but I cant tell what, can anyone see whats wrong?
CodePudding user response:
Now
is the complete date with time. You need to compare it to a complete date with time.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
If Button1.BackColor = Color.Red And DateTime.Now > New DateTime(Now.Year, Now.Month, Now.Day, 11, 48, 0) Then
Button1.BackColor = Color.Black
End If
End Sub
CodePudding user response:
In addition to Mary's answer, you can check just the TimeOfDay
from DateTime.Now
against a TimeSpan
:
Private targetTime As New TimeSpan(11, 48, 0)
Private Sub CAButton_Click(sender As Object, e As EventArgs) Handles CAButton.Click
If CAButton.BackColor = Color.Red And DateTime.Now.TimeOfDay >= targetTime Then
CAButton.BackColor = Color.Black
End If
End Sub
CodePudding user response:
You can achieve that with a Timer which is set to fire at the desired time, which you can set at the time the button is clicked.
I put a button named CAButton on a new form in a new Windows Forms project with this code:
Public Class Form1
Private caBlackTime As New TimeSpan(19, 0, 0)
Private tim As Timer = Nothing
Private Sub Tim_Tick(sender As Object, e As EventArgs)
tim.Stop()
If CAButton.BackColor = Color.Red Then
CAButton.BackColor = Color.Black
End If
End Sub
Private Sub CAButton_Click(sender As Object, e As EventArgs) Handles CAButton.Click
If tim IsNot Nothing Then tim.Dispose()
Dim timeUntilChangeColour = caBlackTime - DateTime.Now.TimeOfDay
If timeUntilChangeColour > TimeSpan.Zero Then
CAButton.BackColor = Color.Red
tim = New Timer With {.Interval = CInt(timeUntilChangeColour.TotalMilliseconds)}
AddHandler tim.Tick, AddressOf Tim_Tick
tim.Start()
Else
CAButton.BackColor = Color.Black
End If
End Sub
Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles MyBase.FormClosing
' Tidy up
If tim IsNot Nothing Then tim.Dispose()
End Sub
End Class
There are several sorts of Timer available, but this one is the Windows.Forms.Timer, which is the most suitable in this particular case.
CodePudding user response:
Ah, @AndrewMorton beat me to it! Well I'm not going to let all this code go to waste...
Here is a solution which sets the color then sets it back automatically, without any button click, at specified intervals daily. Yes, daily - if the application is left open then it will happen tomorrow, and the next day, etc. The colors and time of day of each color are configurable. It also handles the case when the time has already passed when the user starts the application, and the case when the user starts the application between red and black. I use System.Threading.Timer
here. Note: the accuracy of using any timer in .NET may drift over time.
' declare the timers, will be initialized in Form_Load
Private turnColor1Timer As System.Threading.Timer
Private turnColor2Timer As System.Threading.Timer
' set the two colors at this level for a single point of configuration
Private ReadOnly color1 As Color = Color.Red
Private ReadOnly color2 As Color = Color.Black
' first color time is set here for ease of configuration
Private ReadOnly color1TimeOfDay As New TimeSpan(11, 48, 0)
' second color time is set here based on previous color some timespan, for ease of configuration
Private ReadOnly color2TimeOfDay As New TimeSpan(color1TimeOfDay.Add(New TimeSpan(0, 1, 0)).Ticks)
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
' not sure if you want initial state to be black?
turnColorTimerTick(color2)
' initialize the times to change colors to today
Dim turnColor1Time = DateTime.Now.Date.Add(color1TimeOfDay)
Dim turnColor2Time = DateTime.Now.Date.Add(color2TimeOfDay)
' check if that time has already passed today, if so set to tomorrow and change color
If turnColor1Time.CompareTo(DateTime.Now) < 0 Then
turnColorTimerTick(color1)
turnColor1Time = turnColor1Time.AddDays(1)
End If
If turnColor2Time.CompareTo(DateTime.Now) < 0 Then
turnColorTimerTick(color2)
turnColor2Time = turnColor2Time.AddDays(1)
End If
' initialize both timers to their appropriate times
turnColor1Timer = New System.Threading.Timer(AddressOf turnColorTimerTick, color1, CInt(turnColor1Time.Subtract(DateTime.Now).TotalMilliseconds), CInt(TimeSpan.FromDays(1).TotalMilliseconds))
turnColor2Timer = New System.Threading.Timer(AddressOf turnColorTimerTick, color2, CInt(turnColor2Time.Subtract(DateTime.Now).TotalMilliseconds), CInt(TimeSpan.FromDays(1).TotalMilliseconds))
End Sub
Private Sub turnColorTimerTick(state As Object)
' since it ticks in a background thread, must check if you need to invoke back to UI and call Invoke as needed
If CAButton.InvokeRequired Then
CAButton.Invoke(New Action(Of Object)(AddressOf turnColorTimerTick), {state})
Else
' get color from argument passed
Dim color = DirectCast(state, Color)
CAButton.BackColor = color
End If
End Sub
' this is put here because the timers should be disposed of
' if you choose to do this, you must remove Dispose from Form.Designer code
' (compiler error will alert you of this if you don't)
' of course, you could just modify the Dispose in Form.Designer,
' but I like to keep any code I have modified in the Form code instead
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
Try
If disposing Then
components?.Dispose()
End If
turnColor1Timer?.Dispose()
turnColor2Timer?.Dispose()
Finally
MyBase.Dispose(disposing)
End Try
End Sub