...und wieder mal der gute alte CountDown...

  • VB.NET

Es gibt 5 Antworten in diesem Thema. Der letzte Beitrag () ist von picoflop.

    ...und wieder mal der gute alte CountDown...

    Hi,
    ich schreib immernoch an meiner Wettkampftafel rum. Vieles habe ich schon hinbekommen. Nun kommt nur ncoh der CountDown.

    Grundlage:
    Der Countdown soll von wahlweise 1:30, 2:00, 3:00 oder 4:00 Minuten nach unten zählen. Wenn der Schiedsrichter den Kampf unterbricht, muss die Uhr angehalten werden. Wenn der Schiedsrichter den Kampf wieder freigibt, dann soll die Uhr weiterlaufen - also z.B. bei einer Restkampfzeit von 1:21 hab ich unterbrochen, dann Kampfreigabe - und die Uhr soll bei 1:21 wieder weiter nach unten zählen ( Bin schon halb besoffen vom Programmieren - hoffe, ihr könnt mir folgen...)
    Der Typ, der den Countdown bedient, soll NUR (!!) die Leertaste bedienen. Leertaste hat also mehrere Funktionen, siehe weiter unten.


    Start, Stop und Pause hab ich im Countdown per Leertaste mehr oder minder schön hinbekommen,
    Folgendes Problem mit dem Runterzählen der Kampftzeit hab ich aber noch:
    Wenn ich also mittendrin unterbreche, zeigt mir der Countdown prötzlich die VOLLe Kampfzeit (also z.B. 1:30) an. Wenn ich dann wieder auf die Leertaste hämmer, dann zählt er merkwürdigerweise am richtigen Standort weiter nach unten.
    Hier der Code.
    Die variablen "sek" und "min" sind jeweils Public als Integer definiert:

    VB.NET-Quellcode

    1. Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
    2. If sek <> 0 Then
    3. Label17.Text = sek
    4. Label15.Text = min
    5. End If
    6. Label17.Text = (Label17.Text - 1).ToString("00")
    7. sek = Label17.Text
    8. If Label17.Text = -1 Then
    9. Label17.Text = 59
    10. Label15.Text = Label15.Text - 1
    11. min = Label15.Text
    12. End If
    13. If Label15.Text = -1 Then
    14. Timer1.Stop()
    15. Label15.Text = 0
    16. Label17.Text = "00"
    17. My.Computer.Audio.Play("E:\WK-Tafel\HornLang.wav", AudioPlayMode.Background)
    18. End If
    19. End Sub
    20. Private Sub Button1_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles Button1.KeyDown
    21. If e.KeyCode = Keys.Space AndAlso z = 0 Then
    22. z = 1
    23. Timer1.Start()
    24. Label15.Text = min
    25. Label17.Text = sek
    26. ElseIf e.KeyCode = Keys.Space AndAlso z = 1 Then
    27. z = 0
    28. Timer1.Stop()
    29. Label15.Text = min
    30. Label17.Text = sek
    31. End If
    32. End Sub
    33. Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    34. Label15.Text = 1
    35. Label17.Text = 30.ToString("00")
    36. End Sub


    Ich hoffe, ich hab alles richtig erläutert. So soll es sein:

    - Kampfstart (z.B. 1:30 Minuten Kampfzeit) -> durch Drücken der Leertaste
    - Kampfunterbrechung (z.B. bei 1:21 Minuten Restzeit) -> durch Drücken der Leertaste
    - Kampffortsetzung (ab 1:21 Minuten) -> durch drücken der Leertaste
    Irgendwie ist dein Code etwas komisch. Naja geh doch einfach einmal alles in Einzelschritten durch. Vor allem die Stelle an der du stoppst. Sieh dir da mal den Inhalt von min und sek an. Da müsste eigentlich die Stelle sein an der was falsch läuft.

    Mfg
    Firestorm
    Hier mal ein "schöner" Ansatz, auch wenns quick and dirty ist ;)

    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public Class CountDownEventsArgs
    2. Inherits System.EventArgs
    3. Public TimeRemaining As TimeSpan
    4. End Class
    5. Public Enum CountDownStatus
    6. Running
    7. Paused
    8. Stopped
    9. End Enum
    10. Public Class CountDown
    11. Private t As TimeSpan
    12. Private current As Long = 0
    13. Private st As CountDownStatus = CountDownStatus.Stopped
    14. Private WithEvents tm As New Timers.Timer With {.AutoReset = True, .Enabled = False, .Interval = 50}
    15. Public Event Tick(ByVal sender As Object, ByVal e As CountDownEventsArgs)
    16. Public Event Stopped(ByVal sender As Object, ByVal e As CountDownEventsArgs)
    17. Public Sub New(ByVal tm As TimeSpan)
    18. t = tm
    19. End Sub
    20. Public Sub New(ByVal Seconds As Integer)
    21. t = New TimeSpan(0, 0, Seconds)
    22. End Sub
    23. Public Sub New(ByVal minutes As Integer, ByVal Seconds As Integer)
    24. t = New TimeSpan(0, minutes, Seconds)
    25. End Sub
    26. Public Sub New(ByVal hours As Integer, ByVal minutes As Integer, ByVal seconds As Integer)
    27. t = New TimeSpan(hours, minutes, seconds)
    28. End Sub
    29. Public ReadOnly Property Status() As CountDownStatus
    30. Get
    31. Return st
    32. End Get
    33. End Property
    34. Public Sub Start()
    35. If Not st = CountDownStatus.Running Then
    36. If current = 0 Then current = t.TotalMilliseconds
    37. st = CountDownStatus.Running
    38. tm.Enabled = True
    39. End If
    40. End Sub
    41. Public Sub Pause()
    42. If st = CountDownStatus.Running Then
    43. st = CountDownStatus.Paused
    44. tm.Enabled = False
    45. End If
    46. End Sub
    47. Public Sub [Stop]()
    48. current = 0
    49. st = CountDownStatus.Stopped
    50. tm.Enabled = False
    51. Dim d As [Delegate] = StoppedEvent
    52. Dim ev As New CountDownEventsArgs
    53. ev.TimeRemaining = TimeSpan.FromMilliseconds(0)
    54. For Each o As [Delegate] In d.GetInvocationList
    55. If TypeOf o.Target Is Control Then
    56. DirectCast(o.Target, Control).Invoke(d, New Object() {Me, ev})
    57. Else
    58. o.DynamicInvoke(New Object() {Me, ev})
    59. End If
    60. Next
    61. End Sub
    62. Private Sub tm_Elapsed(ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs) Handles tm.Elapsed
    63. If st = CountDownStatus.Running Then
    64. If current > tm.Interval Then
    65. Dim s As Integer = TimeSpan.FromMilliseconds(current).Seconds
    66. current -= tm.Interval
    67. Dim tx As TimeSpan = TimeSpan.FromMilliseconds(current)
    68. If tx.Seconds <> s Then
    69. Dim d As [Delegate] = TickEvent
    70. Dim ev As New CountDownEventsArgs
    71. ev.TimeRemaining = New TimeSpan(tx.Hours, tx.Minutes, tx.Seconds)
    72. For Each o As [Delegate] In d.GetInvocationList
    73. If TypeOf o.Target Is Control Then
    74. DirectCast(o.Target, Control).Invoke(d, New Object() {Me, ev})
    75. Else
    76. o.DynamicInvoke(New Object() {Me, ev})
    77. End If
    78. Next
    79. End If
    80. Else
    81. Me.Stop()
    82. End If
    83. End If
    84. End Sub
    85. End Class


    Bsp.:

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private WithEvents cd As New CountDown(10)
    3. Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    4. If cd.Status = CountDownStatus.Paused OrElse cd.Status = CountDownStatus.Stopped Then
    5. cd.Start()
    6. ElseIf cd.Status = CountDownStatus.Running Then
    7. cd.Pause()
    8. End If
    9. End Sub
    10. Private Sub cd_Stopped(ByVal sender As Object, ByVal e As CountDownEventsArgs) Handles cd.Stopped
    11. Label1.Text = "game over"
    12. End Sub
    13. Private Sub cd_Tick(ByVal sender As Object, ByVal e As CountDownEventsArgs) Handles cd.Tick
    14. Label1.Text = e.TimeRemaining.ToString()
    15. End Sub
    16. End Class


    Wir "bauen" uns also einfach eine entsprechende Stopuhr, die uns jeweils per Event mitteilt, dass sich die Zeit geändert hat, bzw das die Zeit abgelaufen ist.

    EDIT: Da der interne Timer viel zu ungenau ist und die Berechnung mit Timer.Interval demzufolge irgendwie Müll ist, arbeite ich gerade an einer Version die den High Performance timer für die Zeitmessung verwendet (der normale Timer gibt weiter den Takt an geht aber nicht mehr in die Berechnung ein). Das sollte dann hoffentlich eine Genauigkeit < 1ms ermöglichen. Sobald die Version fertig ist, stell ich die mal in den Sourcecode-Austausch.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „picoflop“ ()