Problem mit Countdown im Format "hhh:mm:ss"

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 17 Antworten in diesem Thema. Der letzte Beitrag () ist von ErfinderDesRades.

    Problem mit Countdown im Format "hhh:mm:ss"

    Hallo an alle,

    ich habe folgendes Problem, bei welchem ich auch mit Google nicht weiterkomme. Ich habe eine Zeitangabe im Format "hhh:mm:ss". Dabei habe ich nicht aus versehen 3 Mal das "h" geschrieben sondern möchte damit ausdrücken, dass es sich bei "584:12:25" um 584 Stunden 12 Minuten und 25 Sekunden handelt. Die Umwandlung dieses Strings in Sekunden habe ich ohne Probleme mit folgender Funktion hinbekommen:

    VB.NET-Quellcode

    1. Public Function timeToSec(ByVal time As String)
    2. Dim Einzelteile() As String
    3. Dim dur As String
    4. Dim sec As Integer
    5. dur = time
    6. Einzelteile = dur.Split(":")
    7. sec = (CInt(Einzelteile(0)) * 3600) + (CInt(Einzelteile(1)) * 60) + CInt(Einzelteile(2))
    8. Return sec
    9. End Function


    Auch die umgekehrte Konvertierung ist mit folgendem Code möglich:


    VB.NET-Quellcode

    1. Public Function secToTime(ByVal sec As Integer)
    2. Dim ts As New TimeSpan(0, 0, sec)
    3. Dim hoursStr As String
    4. hoursStr = String.Format("{0:00}:{1:00}:{2:00}", ts.TotalHours, ts.Minutes, ts.Seconds)
    5. Return hoursStr
    6. End Function


    Nun habe ich die Funktion secTo Time in einem Timer.Tick Event angewendet und möchte damit erreichen, dass die Zeit im "hhh:mm:ss"-Format rückwärts läuft. Es wird hier ein gefülltes ListView Zeile für Zeile durchgegangen (inklusive Markierung) und die in einer Spalte vorgegebene Zeit in einer anderen Spalte runtergezählt (im Format "hhh:mm:ss").

    VB.NET-Quellcode

    1. Private Sub Timer5_Tick(sender As Object, e As EventArgs) Handles Timer5.Tick
    2. Dim sec1 As Integer
    3. Dim z As Integer
    4. sec1 = timeToSec(ListView1.Items(timr).SubItems(5).Text)
    5. ListView1.Items.Item(timr).Selected = True
    6. ListView1.Focus()
    7. ListView1.Items(timr).SubItems(5).Text = secToTime(sec1 - 1)
    8. If sec1 = 1 Then
    9. timr = timr + 1
    10. End If
    11. If timr = ListView1.Items.Count Then
    12. If CInt(lbl_loops_ist.Text) = CInt(txt_Loop.Text) Then
    13. If CInt(lbl_cycles_ist.Text) = CInt(txt_cycles.Text) Then
    14. Timer5.Stop()
    15. MsgBox("Programm beendet")
    16. Exit Sub
    17. End If
    18. lbl_cycles_ist.Text = CStr(CInt(lbl_cycles_ist.Text) + 1)
    19. lbl_loops_ist.Text = "0"
    20. End If
    21. lbl_loops_ist.Text = CStr(CInt(lbl_loops_ist.Text) + 1)
    22. For z = 0 To ListView1.Items.Count - 1
    23. ListView1.Items(z).SubItems(5).Text = ListView1.Items(z).SubItems(3).Text
    24. Next
    25. timr = 0
    26. End If
    27. End Sub


    Nun dachte ich stolzerweise es klappt, aber leider funktioniert das nur bis zum Übergang von 100:00:00 auf 99:59:59. Weil dann fängt er an die Stunden wieder hochzuzählen. Also nicht 100, 99, 98, 97 sondern 100, 101, 102, 102.. und so weiter.

    Kann mir jemand auf die Sprünge helfen woran das liegt?

    Ich danke schonmal fürs Lesen und würde mich natüelich über eine hilfreiche Antwort sehr freuen. Und falls jemand noch eine effizientere Idee hat, wie man das ganze anders lösen könnte, dann wäre ich auch sehr daran interessiert.

    Gruß EmBee

    embee83 schrieb:

    Nun habe ich die Funktion secTo Time in einem Timer.Tick Event angewendet und möchte damit erreichen, dass die Zeit im "hhh:mm:ss"-Format rückwärts läuft. Es wird hier ein gefülltes ListView Zeile für Zeile durchgegangen (inklusive Markierung) und die in einer Spalte vorgegebene Zeit in einer anderen Spalte runtergezählt (im Format "hhh:mm:ss").
    Das verstehe ich nicht.

    Was ist nun problem: Welche Methode funktioniert nicht richtig? StringToSec oder SecToString?
    Es funktionieren beide Funktionen.

    Um es vielleicht besser auf den Punkt zu bringen:

    Mit einem Timer zähle ich eine Sekunde von einer Zeitspanne im Format "hhh:mm:ss" runter.

    Das geschieht mit der Zeile:

    embee83 schrieb:

    VB.NET-Quellcode

    1. ListView1.Items(timr).SubItems(5).Text = secToTime(sec1 - 1)


    Funktioniert wie gesagt bis zum oben beschriebenen Übergang gut. Dann leider nicht mehr... :(
    Aber wie bekomme ich es denn hin von 100 Stunden 0 Minuten und 0 Sekunden eine Sekunde abzuziehen und es dann als 99 Stunden 59 Minuten und 59 Sekunden formatiert als 99:59:59 anzuzeigen? Bzw. wie bekomme ich die Zeitspanne ausgegeben, dass er aus 25 Stunden nicht einen Tag und 1 Stunde macht?
    Ist das hier

    VB.NET-Quellcode

    1. ​Public Function secToTime(ByVal sec As Integer)
    2. Dim ts As New TimeSpan(0, 0, sec)
    3. Dim hoursStr As String
    4. hoursStr = String.Format("{0:00}:{1:00}:{2:00}", ts.TotalHours, ts.Minutes, ts.Seconds)
    5. Return hoursStr
    6. End Function


    keine Funktion TimeSpan? Oder meinst du noch was anderes?

    Und ist es unersichtlich, dass timeToSec einen Integerwert zurückgibt und secToTime einen String?
    Nein, keine Funktion Timespan. Die Methode gibt doch Object zurück, und auf keinen Fall ein Timespan-Objekt.

    Weil wenn du keinen Rückgabetyp deklarierst, wird tatsächlich nur der Datentyp Object zurückgegeben. Folge mal dem Tutorial, was ich verlinkt habe.
    Das ist ganz entscheidend, denn inne OOP ist es fundamental, Datentypen klar voneinander zu unterscheiden, und jeweils zielführend einzusetzen. Und die blöden Voreinstellungen - die du auch noch drin hast - verhindern leider sehr effektiv, Datentypen klar wahrzunehmen.

    Aber hier mal mein SpecialFormat:

    VB.NET-Quellcode

    1. Private Function SpecialFormat(ts As TimeSpan) As String
    2. Return String.Format("{0}:{1:mm\:ss}", ts.Days * 24 + ts.Hours, ts)
    3. End Function
    Da siehst du zB am Methodenkopf, welchen Datentyp das Ding zurückgibt.
    Und diese Info zeigt dir dann auch Intellisense beim Coden an, wo immer du das Teil benutzst. Und wenn du dem Tut folgst, sorgt darüberhinaus der Compiler dafür, dass du diese Methode überhaupt nicht falsch einsetzen kannst.
    Ok...erst einmal danke ich Dir für deine Hinweise und den Link...ich werde mich intensiv damit beschäftigen bevor ich weiter mache. Auch danke ich die für deinen Code-Schnipsel :) Allerdings würde ich gerne noch wissen, warum die Stunden statt rückwärts ab 100 wieder vorwärts laufen. Das kann eigentlich nicht am Format liegen oder?
    ich keine Ahnung.
    Der Code ist viel zu undurchsichtig, und greift auf lauter Elemente zu, deren Wert ich nicht kenne. Was weiß ich denn, was in lbl_loops_ist.Text, txt_Loop.Text, txt_cycles.Text oder ListView1.Items(timr).SubItems(5).Text steht?

    Ich würde einen Countdown einfach so bauen, dass ich mir eine Zielzeit merke, und im Timer-Tick immer die Differenz ZielZeit-Date.Now ermittel - das wäre auch der Timespan, den man anzeigen könnte.
    Hat dieser Timespan einen Wert <= 0, dann ist der CountDown wohl durch.

    Auf diese einfache Weise hängt mein CountDown von nur einer einzigen Variablen ab, und nicht von zig Textboxen und einer Listview, wo überall immer was anneres drinne stehen kann.

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

    Ich habe mal ein Bild von der ListView angehängt...

    In der 4 Spalte steht die Solldauer eines Steps. Diese wird mit einem Timer (Interval 1000) in Spalte 6 runtergezählt, bis es in die nächste Zeile geht. Ist das Ende der Liste erreicht ist eine Schleife durchlaufen und lbl_loops_ist.Text wird um eins hochgezählt. Das wird solange wiederholt bis die Anzahl der Schleifen txt_Loop.Text durlaufen sind, um dann txt_Cycles.Text einen hochzuzählen. Sind alle Zyklen durchlaufen wird der Timer gestoppt das Prüfprogramm ist beendet. Funktioniert wie gesagt wunderbar bis die Stundenangabe von 100 auf 99 wechseln soll.

    Ich hoffe es ist jetzt etwas verständlicher.
    Bilder
    • Beispiel.PNG

      12,66 kB, 538×334, 95 mal angesehen

    ErfinderDesRades schrieb:

    Ich würde einen Countdown einfach so bauen, dass ich mir eine Zielzeit merke, und im Timer-Tick immer die Differenz ZielZeit-Date.Now ermittel


    Ok...ZielZeit ist dann was genau? Eine Uhrzeit? Oder eine Zeitspanne ? Ich habe jetzt dein "SpecialFormat" eingebaut und das funktioniert fabelhaft und dafür danke ich Dir. Aber mit deiner Herangehensweise stehe ich ein bisschen auf dem Schlauch. Ich stoße mich immer an dem Begriff "Zeit". Aber es soll ja eine Zeitspanne ablaufen...vielleicht kannst du mir da mit ein paar erklärenden Worten unter die Arme greifen. Natürlich auch jeder andere...:)

    Hier mein aktueller Quelltext:

    VB.NET-Quellcode

    1. Private Sub Timer5_Tick(sender As Object, e As EventArgs) Handles Timer5.Tick
    2. Dim sekunden As Integer = CInt(timeToSec(ListView1.Items(timr).SubItems(5).Text))
    3. Dim sec1 As TimeSpan = New TimeSpan(0, 0, sekunden - 1)
    4. Dim z As Integer
    5. ListView1.Items.Item(timr).Selected = True
    6. ListView1.Focus()
    7. ListView1.Items(timr).SubItems(5).Text = SpecialFormat(sec1)
    8. If CInt(timeToSec(ListView1.Items(timr).SubItems(5).Text)) = 0 Then
    9. timr = timr + 1
    10. End If
    11. If timr = ListView1.Items.Count Then
    12. If CInt(lbl_loops_ist.Text) = CInt(txt_Loop.Text) Then
    13. If CInt(lbl_cycles_ist.Text) = CInt(txt_cycles.Text) Then
    14. Timer5.Stop()
    15. MsgBox("Programm beendet")
    16. Exit Sub
    17. End If
    18. lbl_cycles_ist.Text = CStr(CInt(lbl_cycles_ist.Text) + 1)
    19. lbl_loops_ist.Text = "0"
    20. End If
    21. lbl_loops_ist.Text = CStr(CInt(lbl_loops_ist.Text) + 1)
    22. For z = 0 To ListView1.Items.Count - 1
    23. ListView1.Items(z).SubItems(5).Text = ListView1.Items(z).SubItems(3).Text
    24. Next
    25. timr = 0
    26. End If
    27. End Sub

    Eine Zeit ist ein Zeitpunkt, DateTime.
    Eine Zeitspanne ist eine Zeitspanne, Timespan.
    DateTime + TimeSpan kann man addieren, kommt ein Datetime bei raus.

    Mit ZielZeit ist der Zeitpunkt gemeint, nachdem der Timer nicht mehr weiter laufen soll. Soll der Timer also 900s laufen, erstell einen entsprechenden Timespan, addiere ihn auf Date.Now, und du hast die Ziel-Zeit.
    Hmm...ich habe jetzt folgendes:

    VB.NET-Quellcode

    1. Private Sub Timer6_Tick(sender As Object, e As EventArgs) Handles Timer6.Tick
    2. Dim target_span As TimeSpan = New TimeSpan(0, 0, 0, 900, 0)
    3. Dim target As DateTime
    4. target = DateTime.Now + target_span
    5. TextBox6.Text = CStr(target) 
    6. End Sub


    Aber die Zeit läuft vorwärts und zeigt Datum und Uhrzeit an. Wie bekomme ich das ganze jetzt dazu, dass er mir die verbleibende Zeit rückwärts zählend anzeigt?