VB.NET Timer Countdown
Inhaltsverzeichnis
- 1 VB.NET Timer Countdown
- 2 Vorschau – VB.NET Timer Countdown
- 3 Das erste Beispiel – auf einer Form mit Label
- 4 VB.NET Timer Countdown die Zweite – auf einer Form mit GDI+
- 4.1 Benötigte Steuerelemente
- 4.2 Styling der Komponenten
- 4.3 Der Code
- 5 Downloads
VB.NET Timer Countdown
Du fragst Dich, wie Du in VB.NET einen Timer Countdown erstellen kannst? Lerne in diesem Beitrag wie!
Falls Du noch gar nichts über das Timer-Control weißt, empfehle ich Dir, meinen allgemeinen Beitrag über das VB.NET Timer Steuerlement anzusehen.
Ergänzend dazu habe ich auch noch einen weiteren Beitrag über die dynamische Erstellung eines Timers zur Laufzeit geschrieben.
Vorschau – VB.NET Timer Countdown
Hier drunter siehst Du, wie die Umsetzung eines Countdowns zum Beispiel aussehen könnte.
Das erste Beispiel – auf einer Form mit Label
Ich denke als erstes und beliebtestes Beispiel, kommt einem die Umsetzung auf einer Form in den Sinn.
Daher machen wir es uns einfach und beginnen direkt damit 😊!
Alles was Du dafür letztendlich brauchst, hast du mit wenigen Handgriffen zusammengeklickt!
Benötigte Steuerelemente
Form
Wir haben uns hierbei entschieden, den Countdown auf einer Form darzustellen, daher brauchen wir natürlich eine Form.
Timer
Für dieses Beispiel brauchen wir selbstverständlich einen Timer, wer hätte das gedacht.. Zack, rauf auf die Form, oder im Code der Klasse als WithEvents Variable/Eigenschaft deklariert – wie Du möchtest.
Hier habe ich den Timer übrigens tmrCountdown genannt, Du solltest natürlich auch einen vernünftigeren Namen als „Timer1“ wählen 😉!
Label
Zu guter Letzt hatten wir geplant, den Countdown selbst – also die Zahlen – in einem Label darzustellen. Ziehe daher ein Label auf die Form.
Auch dem Label wurde ein aussagekräftigerer Name als „Label1“ verpasst. Hier habe ich das Label „lblNumber“ genannt.
Styling der Komponenten
Im folgenden Schritt kümmern wir uns ein wenig um das Styling der Controls, auch wenn wir hier natürlich keine Spiel-like-Grafik haben werden, kann es ja zumindest ein wenig „schöner“ werden.
Die Form stylen
Um das Ganze ein wenig sichtbarer zu gestalten, nehmen wir uns zuerst die Eigenschaften der Form vor.
Ich würde vorschlagen, die Eigenschaft „StartPosition“ der Form auf „CenterScreen“ zu stellen.
Wie der Name schon sagt, wird die Form so standardmäßig zentriert auf dem Bildschirm angezeigt.
Die Hintergrundfarbe der Form, also die „BackColor“ habe ich auf „Black“ gestellt. So haben wir einen guten Kontrast, Welcher irgendwie an ein Kino erinnert.
Für die Größe der Form habe ich 189×253 gewählt, ist natürlich auch Dir überlassen!
Die Anzeige in einem Label
Wir verpassen dem Label eine ausreichende Größe, also so ungefähr eine Font-Größe von 120.
Anschließend habe ich mich für die Schriftart Consolas entschieden, Welche übrigens die Standard-Schrift von Visual Studio ist.
Zuletzt bekommt das Label die Schriftfarbe „White“, um den oben angesprochenen Kontrast zu bekommen.
Der Code
Im nächsten Abschnitt kommen wir zu dem Code, den wir benötigen um das VB.NET Timer Countdown Beispiel zum Laufen zu bekommen.
Das Timer Tick-Ereignis
Zuerst nehmen wir das Tick-Ereignis des Timers – klicke z. B. doppelt auf den Timer, oder wähle das Ereignis über Designer und Co. aus:
Private Sub tmrCountdown_Tick(sender As Object, e As EventArgs) Handles tmrCountdown.Tick Dim currentNumber = Convert.ToInt32(lblNumber.Text) Dim countDownFinished = currentNumber = 0 If countDownFinished Then tmrCountdown.Stop() MessageBox.Show("Countdown finished") Return End If currentNumber -= 1 lblNumber.Text = currentNumber.ToString() End Sub
FormClosing-Ereignis – sauber schließen
Um die Form sauber zu schließen, sprich die Arbeit vorher korrekt zu beenden, fügen wir folgenden Ereignishandler hinzu.
Dieser sorgt dafür, dass der Timer beim Schließen der Form gestoppt wird.
Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing tmrCountdown.Stop() End Sub
Auch wenn der Timer vermutlich durch die Assoziation zur Form (wenn man Ihn per Drag & Drop auf die Form zieht) automatisch disposed wird, ist ein Gedanke daran nicht verkehrt.
Denn auch in Zukunft sollte man solche Sachen nach Möglichkeit bedenken, um z. B. potentielle Memory-Leaks, etc. zu vermeiden.
Den Countdown starten
Ich habe mich dazu entschieden, den Timer durch einen Klick auf das Label starten zu lassen.
Auch hierzu kann man einen Doppelklick auf das Label machen, oder über den Designer arbeiten.
Private Sub lblNumber_Click(sender As Object, e As EventArgs) Handles lblNumber.Click tmrCountdown.Start() End Sub
Wenn man möchte, dass der Timer beim Start des Programms sofort loslegt, kann statt dem vorherigen Code natürlich auch die Enabled-Eigenschaft des Timers bereits im Designer auf True stellen.
VB.NET Timer Countdown die Zweite – auf einer Form mit GDI+
Im zweiten zwar etwas schwierigeren, jedoch interessanteren Beispiel, schauen wir uns das Zeichnen des Countdowns mit GDI+ an.
Dies wäre zum Beispiel nützlich, wenn Du vorhast ein eigenes kleines Spiel mit VB.NET zu entwickeln.
Hier kümmern wir uns nun selbst um das Zeichnen des Countdowns, statt Ihn durch ein Label darzustellen.
Benötigte Steuerelemente
Statt wie bei den Steuerelementen des ersten Beispiels ein Label zu verwenden, verzichten wir hier darauf. Wir übernehmen die Darstellung des Countdowns mit GDI+ und zeichnen selbst.
Styling der Komponenten
Hier verfahren wir ähnlich wie oben, daher ist es kein großer Mehraufwand.
Der Code
3 Eigenschaften kommen in der Form hinzu
Public Property CurrentNumber As Integer Public Property CountdownFont As Font Public Property CountdownBrush As Brush
Mir ist an dieser Stelle wichtig, die Eigenschaften im Konstruktor nur ein einziges Mal zuzuweisen und anschließend nur noch abrufen zu müssen.
Bei vielerlei Code der so im Netz tummelt, stellt man fest, dass vor Allem Anfänger, „faulere Leute“ und die „Copy & Paster“ in jedem Durchlauf z. B. die Instanz des Fonts, usw. immer wieder neu erstellen – ein Graus..
Ein ressourceneffizientes arbeiten ist für mich persönlich sehr wichtig, auch wenn man freilich nicht immer an alles denken kann..
CurrentNumber
Die CurrentNumber stellt wie der Name schon sagt unsere aktuelle Countdown-Zahl dar.
Da wir in diesem Beispiel ja nicht mehr den Inhalt des Labels als Zwischenspeicher der Zahl missbrauchen können, ist dies eine der richtigen Alternativen.
Zum einen erleichtert die klassenweite Deklaration den Zugriff aus verschiedenen Methoden und zum anderen fühlt sich die Assoziation zur Form hier richtig an.
CountdownFont
Mit dieser Eigenschaft bestimmen wir den Font des Countdowns.
Hier gilt es zu beachten, dass ein Font nicht schlichtweg nur den Namen des Fonts, sondern auch Styling-Informationen wie Größe und Stärke/Dicke enthält.
Wie im vorherigen Beispiel habe ich die Schriftart bei Consolas und die Größe bei 120 belassen.
Hier habe ich auch wie oben den „FontStyle“ auf dick, also auf „Bold“ gesetzt.
CountdownBrush
Der Brush ist sozusagen die Farbe die wir für den selbst gezeichneten Countdown verwenden.
Wir verwenden auch hier die Farbe „White“, indem wir auf Brushes.White zugreifen.
Konstruktor
Sub New() InitializeComponent() DoubleBuffered = True CurrentNumber = 5 CountdownFont = New Font("Consolas", 120, FontStyle.Bold) CountdownBrush = Brushes.White End Sub
Im Konstruktor weisen wir einmalig alles zu, was wir für unsere Arbeit brauchen.
Natürlich ist die CurrentNumber hier eine Ausnahme, da diese sich ja durch den Countdown verändern wird.
Neu könnte für Dich hier ggf. die Eigenschaft namens DoubleBuffered sein.
An dieser Stelle reicht denke ich die Erklärung, dass die Eigenschaft das eventuelle Flackern der Form beim Zeichnen ein wenig besser in den Griff bekommt.
Das Zeichnen des Countdowns mit GDI+
„Das Beste kommt zum Schluss„, heißt es doch immer so schön!
Nun kommen wir zum Code, der für das Zeichnen des Countdowns verantwortlich ist.
Private Sub Form1_Paint(sender As Object, e As PaintEventArgs) Handles Me.Paint Dim numberString = CurrentNumber.ToString() Dim numberStringSize = e.Graphics.MeasureString(numberString, CountdownFont) Dim centerX = (ClientRectangle.Width / 2) - (numberStringSize.Width / 2) Dim centerY = (ClientRectangle.Height / 2) - (numberStringSize.Height / 2) Dim centerOfForm = New Point(centerX, centerY) e.Graphics.DrawString(numberString, CountdownFont, CountdownBrush, centerOfForm) End Sub
Statt hier „Schlampi-Pampi“ mit der Nummer – also dem Integer – zu hantieren, wandeln wir Diese natürlich vor Gebrauch in einen String namens „numberString“ um.
Danach können wir durch das Graphics-Objekt, Welches uns durch die PaintEventArgs bereitgestellt wird, die Größe des resultierenden Strings messen.
Im darauffolgenden Schritt bestimmen wir jeweils die horizontale und die vertikale Mitte der Form und erstellen eine neue Instanz des Point-Datentyps – praktisch unsere 2D-Koordinaten.
Final können wir die Zahl auf die Form bringen, indem wir die „DrawString„-Methode des e.Graphics Objekts aufrufen.
Diese möchte natürlich alle vorher bestimmten Daten wie den zu zeichnenden String, den Font, einen Brush und letztendlich die Koordinaten wo das Ganze landen soll haben.
Der erste Startversuch
Wenn Du nun einmal F5 drückst, oder das Programm via Visual Studios „Play Knopf“ ins Debugging schickst, siehst Du unsere Zahl „5“.
Leider geht es aber nicht weiter.. Warum? Naja der Timer, Welcher unsere Zahl runterzählt fehlt 😉.
Auch haben wir aktuell das Problem, dass die Zahl verschwindet, wenn Du die Größe der Form beim Debugging veränderst – probiere es ruhig mal aus!
Die verlorene Zahl
Unsere Zahl verschwindet einem aus einem besonders für Anfänger nicht direkt ersichtlichen Grund.
Aktuell zeichnen wir die Zahl nur dann (neu), wenn die Form ihr Paint-Ereignis ausgibt.
Am Anfang ist die Zahl klar sichtbar, weil die Form dieses Ereignis ein Mal bei Start der Anwendung ausgibt.
Um das zu prüfen, könntest Du ja zum Beispiel eine kleine Ausgabe, oder einen Debug-Schritt hinzufügen:
Debug.WriteLine("PAINT")
Invalidate zur Rettung
Wir müssen nun also irgendwie dafür sorgen, dass die Form ihr Paint-Ereignis öfter ausgibt und somit das Zeichnen der Zahl anweisen.
Man könnte jetzt natürlich mit der Brechstange kommen und sowas wie eine Game Loop hinzufügen.
Anderweitig, jedoch genauso heavy könnte man auch einen Timer verwenden und der Form im geringen Intervall sagen: „Hey, zeichne dich neu!“.
Um der Form mitzuteilen, dass Sie sich, oder zumindest gewisse Bereiche neu zeichnen – also invalidieren – soll, können wir mit der Methode „Invalidate“ erreichen.
Wenn nicht jetzt, wann dann – löl?
Auch hier bitte ich wieder um den Schritt zurück, um zu überlegen: „Wann genau brauche ich denn eine Aktualisierung der Zeichnung“.
Oben im Gif-Bild konnten wir erkennen, dass es offensichtlich nach einer Größenveränderung der Form von Nöten wäre.
Somit hätten wir auch direkt die Maximierung der Form mit abgearbeitet, denn auch da verändert Sie ihre Größe.
Fügen wir also folgenden „Resize“-Ereignishandler hinzu:
Private Sub Form1_Resize(sender As Object, e As EventArgs) Handles Me.Resize Invalidate() End Sub
Schon ist unser Problem behoben:
Der Countdown
Zu guter Letzt kommen wir zum Timer selbst, Welcher dafür verantwortlich ist, die Zahl herunterzuzählen.
Den Startschuss geben wir auch hier mit einem Klick-Ereignis, nur dieses mal das Ereignis der Form:
Private Sub Form1_Click(sender As Object, e As EventArgs) Handles Me.Click tmrCountdown.Start() End Sub
Nun noch die paar Zeilen des Timer Tick-Ereignisses – nur dieses Mal ohne Label-Code – hinzufügen:
Private Sub tmrCountdown_Tick(sender As Object, e As EventArgs) Handles tmrCountdown.Tick Dim countDownFinished = CurrentNumber = 0 If countDownFinished Then tmrCountdown.Stop() MessageBox.Show("Countdown finished") Return End If CurrentNumber -= 1 Invalidate() End Sub
Hier daran denken, dass auch nach der Änderung der „CurrentNumber“ ein „Invalidate“ passieren sollte, damit unsere gezeichnete Zahl aktualisiert wird.
Fertig 😄!