Entwickler-Ecke
WinForms - Timer-Problem
YK18415 - Di 03.01.17 16:25
Titel: Timer-Problem
Hallo zusammen,
ich habe zwar schon was in WinForms programmiert, dennoch bin ich ein ziemlicher Anfänger. :)
Ich möchte ein Asteroid-Spiel programmieren. Dazu zeichne ich ein Raumschiff (Dreieck) und Asteroiden (Kreise) in einer pictureBox. Das funktioniert ja auch. Um z. B. die Asteroiden bewegen zu lassen, benutze ich einen Timer, der immer nach einer bestimmten Zeit die Y-Koordinate des Kreises verschiebt (dadurch soll er sich nach unten bewegen).
Mein Vorgehen: Ich ziehe den Timer aus der Toolbox einfach auf meine Form und stelle "Enabled" auf True. "Modifiers" steht bei mir auf Private. Nun klicke ich doppelt auf den Timer, wodurch dieser in Form1.cs erscheint und ich Code schreiben kann.
Mein Problem:
Leider geht der Programmablauf gar nicht erst in diesen Timer-Code hinein... Ich frage mich wieso?
Mein Timer-Code:
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14:
| private void timer1_Tick(object sender, EventArgs e) { foreach (Object item in listBox1.Items) { Asteroid asteroid = item as Asteroid;
if (item is Asteroid) { asteroid.Y += 20; } } pictureBox1.Refresh(); } |
Über Hilfe würde ich mich sehr freuen :D
Moderiert von
Christian S.: C#-Tags hinzugefügt
Ralf Jansen - Di 03.01.17 16:59
Zitat: |
Leider geht der Programmablauf gar nicht erst in diesen Timer-Code hinein... Ich frage mich wieso? |
Hast du das per Debugger rausgefunden? Also weil ein Breakpoint in der Methode nicht gezogen hat oder z.B. nur weil du keine Reaktion auf deiner Form gesehen hast?
Th69 - Di 03.01.17 16:59
Auf welchen Wert steht die Interval-Eigenschaft (also die Zeit in Millisekunden, die der Timer jeweils ausgelöst werden soll)?
YK18415 - Di 03.01.17 17:04
Mein Interval steht auf 1000 ms @Th69
@Ralf Jansen: Beides hat nicht funktioniert. Also es gab keine Reaktion auf der Form und der Debugger ist nicht bis zum Breakpoint gekommen.
Ralf Jansen - Di 03.01.17 17:11
Zu deiner Form1 solltest du auch eine Form1.Designer.cs Datei finden. Darin wirst du Code finden der dem Zusammensetzen des timers entspricht.
Solle ungefähr so in der Datei aussehen.
C#-Quelltext
1: 2: 3: 4: 5: 6: 7:
| this.timer1.Enabled = true; this.timer1.Interval = 1000; this.timer1.Tick += new System.EventHandler(this.timer1_Tick); |
Zeig uns mal bitte wie das bei dir aussieht.
YK18415 - Di 03.01.17 17:14
C#-Quelltext
1: 2: 3: 4: 5: 6:
| this.timer1.Enabled = true; this.timer1.Interval = 1000; this.timer1.Tick += new System.EventHandler(this.timer1_Tick); |
Bei mir sieht es genau so aus.
Moderiert von
Th69: C#-Tags hinzugefügt
Ralf Jansen - Di 03.01.17 17:21
Dann sollten wir erstmal davon ausgehen das der auch aufgerufen wird. Wo hast du in der Methode den Breakpoint beim Debuggen gesetzt? Probier mal den direkt auf die öffnende Klammer der Methode zu setzen.
YK18415 - Di 03.01.17 17:38
Das habe ich getan. Allerdings wird dieser Breakpoint, wenn ich auf F11 oder auch auf F5 drücke, nie abgerufen...
Eben gerade hatte ich das Ereignis, dass mein Kreis doch plötzlich an einer anderen Stelle der pictureBox war, allerdings habe ich diese "Animation" nicht gesehen, da ich mit dem Debugger zur Laufzeit beschäftigt war. Als ich dann alle Breakpoints entfernt habe und ich zur Laufzeit wieder F5 drückte, bewegte sich der Kreis nicht, obwohl er doch irgendwie "gewandert" sein muss???
Könnte es sein, das mein Laptop einfach zu langsam ist, um die Bewegung anzuzeigen?
Ralf Jansen - Di 03.01.17 17:57
Von hier schwer zu sagen. Kommt drauf an wie das konkrete Zeichnen von dir gelöst ist. Den Code kennen wir aber nicht.
YK18415 - Di 03.01.17 18:08
Mein Quellcode:
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59:
| using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using Asteroids_Game_Neu.Properties; using System.Threading; using System.Timers;
namespace Asteroids_Game_Neu { public partial class Form1 : Form { public Form1() { InitializeComponent(); }
private void buttonPlay_Click(object sender, EventArgs e) { Asteroid asteroid = new Asteroid() { x = 300, y = 0, height = (int)numericUpDown1.Value, width = (int)numericUpDown1.Value }; listBox1.Items.Add(asteroid); pictureBox1.Refresh(); }
private void pictureBox1_Paint(object sender, PaintEventArgs e) { foreach (Object item in listBox1.Items) { Asteroid asteroid = item as Asteroid; if (item is Asteroid) { asteroid.Draw(e.Graphics); } } pictureBox1.Refresh(); }
private void timer1_Tick(object sender, EventArgs e) { foreach (Object item in listBox1.Items) { Asteroid asteroid = item as Asteroid;
if (item is Asteroid) { asteroid.Y += 20; } } pictureBox1.Refresh(); } } } |
Zum Zeichnen der Asteroiden habe ich eine extra Klasse erstellt, die die Draw-Methode von meiner Basisklasse überschreibt (weil ich ja noch andere Objekte wie z. B. Raumschiffe usw. zeichnen möchte).
Die Größe des Asteroiden bestimme ich über einen numericUpDown auf meiner Form zur Laufzeit. Wenn ich den button "Play" drücke, wird ein Asteroid gezeichnet und ab da sollte eigentlich auch der Timer laufen...
Es wäre wirklich sehr nett, wenn einer eine Idee hätte, wie ich das Problem mit dem Timer lösen könnte. :D
Danke! ^^
Moderiert von
Christian S.: C#-Tags hinzugefügt
Ralf Jansen - Di 03.01.17 18:55
Ohne da jetzt länger drauf geguckt zu haben fällt mir nur eins auf. Du rufst im Paint Event der PictureBox Refresh der PictureBox auf. Ich bezweifle das das eine gute Idee ist. Also beim zeichnen der PictureBox der PictureBox zu sagen es soll sich doch mal bitte neuzeichnen(und damit erneut ein Paint Event auszulösen). Nimm das zumindest mal raus.
YK18415 - Di 03.01.17 19:10
Danke erstmal für deine Hilfe @Ralf Jansen. :)
Wenn ich das aber rausnehme, wie genau kann dann der Kreis verschoben werden? Ich meine, wenn die pictureBox nicht neugezeichnet wird, bleibt der Kreis doch immer an der gleichen Stelle, auch wenn der Timer aktiv ist? Oder verstehe ich da was grundlegend falsch...?
Was sollte ich stattdessen benutzen? Die Methode Invalidate? Aber ist die nicht so ziemlich das Gleich wie Refresh?
Gruß
YK18415
Th69 - Di 03.01.17 19:24
Nur in der
Paint-Methode diese Methode entfernen, in den anderen ist sie korrekt.
PS: Du verwendest sowohl
as als auch
is (das ist doppeltgemoppelt) - besser:
C#-Quelltext
1: 2: 3: 4: 5: 6:
| Asteroid asteroid = item as Asteroid;
if (asteroid != null) { } |
YK18415 - Di 03.01.17 19:33
Ahhhh, jetzt funktioniert es! :D
Tatsächlich musste ich nur die Refresh-Methode in der Paint-Methode entfernen... :o
Das mit der Abfrage habe ich nun auch korrigiert, stimmt, wäre ja wirklich doppelt... :o
Dankeschön!!! :D
Th69 - Di 03.01.17 20:02
Zur Erklärung: Du hattest eine Endlos-Rekursion beim Zeichnen und deswegen konnte die Timer-Methode nicht aufgerufen werden.
YK18415 - Di 03.01.17 20:04
Ja, hätte ich eigentlich schon beim debuggen merken müssen... :/
Naja, aus Fehlern lernt man. ^^
Danke!
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!