Entwickler-Ecke
Delphi Language (Object-Pascal) / CLX - Timerereignis wird nicht ausgelöst
nn1234 - Fr 30.12.05 10:48
Titel: Timerereignis wird nicht ausgelöst
Hi!
Habe einen Timer gesetzt, der einige Dinge, gleich nach dem Aufruf des Formulars erledigen soll, unter anderem Bitmaps laden, da das mit Fomcreate ja nicht
functioniert (ok, der war schlecht... :lol: ) Wollte jetzt mal fragen, ob es sein kann, dass der Timer zu viele Aktionen beinhaltet, sodass er, wenn ich die Eigenschaft Enable nach Erledigung der Aktionen auf False setze, gar nichts mehr macht? Hier mal der Quelltext:
Delphi-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:
| procedure TfKampf.Timer1Timer(Sender: TObject); var level_Spieler,level_Gegner : Integer;art_Gegner,art_Spieler : String; begin SetViewPortOrgEx(Canvas.Handle,fKampf.width DIV 2,fKampf.height DIV 2,nil);
if fAnfang.RadioGroup1.ItemIndex = 0 then art_Spieler := 'Eis'; if FAnfang.RadioGroup2.ItemIndex = 0 then art_Gegner := 'Erde'; level_Spieler := 1; level_Gegner := 1; life_max_Spieler := TKreatur.create(level_Spieler,art_Spieler); life_max_Gegner := TKreatur.create(level_Gegner,art_Gegner);
if fAnfang.RadioGroup1.ItemIndex = 0 then begin uNuetzlich.kreatur_zeichnen(fKampf.Canvas,'Kreaturen/Eiselement.Bmp',-330,-70); Label5.Caption := 'Eiselement'; uNuetzlich.life_balken(fKampf.Canvas,life_max_Spieler.life_max,life_max_Spieler.life_max,1); Label6.Caption := IntToStr(life_max_Spieler.life_max); Label7.Caption := IntToStr(life_akt_Spieler); Label10.Caption := IntToStr(level_Spieler); end;
if fAnfang.RadioGroup2.ItemIndex = 0 then begin uNuetzlich.kreatur_zeichnen(fKampf.Canvas,'Kreaturen/Erdelement.Bmp',120,-280); Label4.Caption := 'Erdelement'; uNuetzlich.life_balken(fKampf.Canvas,life_max_Gegner.life_max,life_max_Gegner.life_max,2); Label9.Caption := IntToStr(level_Gegner); end;
end; |
Wenn ich jetzt ganz am Schluss Enable auf False setze, macht er gar nichts mehr. Das Intervall hab ich auf 100 gesetzt, hab's aber auch schon mit anderen Intervallen versucht.
nn
Narses - Fr 30.12.05 10:54
Moin!
Alternative: FormShow und ein globales Flag; spart den Timer. :wink:
cu
Narses
nn1234 - Fr 30.12.05 11:04
...Hab keine Ahnung, was flags sind, und wie ich die anwende... :oops:
nn
Narses - Fr 30.12.05 11:17
Moin!
Aaalso... :wink: Du machst die ganzen Aktionen im Ereignis FormShow(). Da du nicht ausschließen kannst, dass das Ereignis mehrfach auftritt, du aber nur das erste Auftreten bearbeiten willst, mußt du dir in einer globalen Variable vom Typ Boolean (z.B.) merken, dass du das schon getan hast. Konkret: gloablen Boolean anlegen und im FormCreate() auf FALSE setzen, im FormShow() nach allen Aktionen auf TRUE und die Aktionen per IF-THEN kapseln.
Auf diese Weise eingesetzte Bools nennt man auch schon mal Flag ("Signalfähnchen" so ganz grob).
cu
Narses
Gausi - Fr 30.12.05 11:21
Da ist wohl so etwas gemeint
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| var Erledigt: Boolean;
Erledigt := False;
if Not Erledigt then begin Erledigt := True; end; |
Sinn: Eine Boolsche Variable, die steuert, ob etwas ausgeführt werden soll, oder nicht. Nach einmaliger Ausführung wird diese Variable so gesetzt, dass das ganze nicht nochmal ausgeführt wird.
Edit: Hab ich wirklich 4 Minuten zum Tippen gebraucht...:gruebel:?
wdbee - Fr 30.12.05 11:25
Das, was du im Timer-Event machst, soll doch nur ein einziges mal ausgeführt werden.
Im FormCreate-Ereignis geht es nicht, wie du sagst. Im FormShow-Ereignis geht es aber. Nur wird dieses Ereignis ggf. mehr als einmal auftreten, anders als FormCreate.
Deshalb musst du dir einfach merken, ob die Objekte, die du da erzeugen willst, schon erzeugt sind oder nicht.
Die Variable life_max_Spieler z.B. sollte nil sein, wenn es das Objekt noch nicht gibt.
Also kannst du einfach abfragen ob life_max_Spieler noch nil ist und nur dann die Initialisierung im FormShow-Ereignis ausführen. Damit verwendest du diese Variable als Flag (Flagge). Flagge oben = Objekt gibt es schon, Flagge unten = Objekt gibt es noch nicht. Ein Flag ist also eine Boolsche-Variable, die als Merker für etwas eingesetzt wird.
Die Verwendung von Timern für soetwas, hat den Nachteil, dass du nicht mehr sicher weißt, wann im Ablauf die Initialisierung ausgeführt wird! Wenn du dennoch einen Timer verwendest, um ein einmaliges Ereignis auszulösen, dann solltest du als erstes im TimerEvent Enabled auf false setzten, dann spielt es keine Rolle mehr, wie lange die Ausführung tatsächlich dauert.
nn1234 - Fr 30.12.05 13:37
Ist mit OnShow die Methode Form2.Show gemeint? Das Ereignis OnShow im Objektinspektor unter Ereignisse lässt sich nicht als Prozedur öffnen... :?
nn
Ja-Pa - Fr 30.12.05 13:44
Genau, Delphi benennt die Ereignisprozeduren immer so (aus Button1.OnClick wird Button1Click).
Kannst sie aber natürlich auch beliebig umbenennen wenn dich das stört :wink:
nn1234 - Fr 30.12.05 13:45
Delphi-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:
| var Erledigt : Boolean; ... procedure TfKampf.FormCreate(Sender: TObject); begin Erledigt := False; end;
procedure TfKampf.FormShow(Sender: TObject); var level_Spieler,level_Gegner : Integer;art_Gegner,art_Spieler : String; begin if not Erledigt then begin
SetViewPortOrgEx(Canvas.Handle,fKampf.width DIV 2,fKampf.height DIV 2,nil);
if fAnfang.RadioGroup1.ItemIndex = 0 then art_Spieler := 'Eis'; if FAnfang.RadioGroup2.ItemIndex = 0 then art_Gegner := 'Erde'; level_Spieler := 1; level_Gegner := 1; life_max_Spieler := TKreatur.create(level_Spieler,art_Spieler); life_max_Gegner := TKreatur.create(level_Gegner,art_Gegner);
if fAnfang.RadioGroup1.ItemIndex = 0 then begin uNuetzlich.kreatur_zeichnen(fKampf.Canvas,'Kreaturen/Eiselement.Bmp',-330,-70); Label5.Caption := 'Eiselement'; uNuetzlich.life_balken(fKampf.Canvas,life_max_Spieler.life_max,life_max_Spieler.life_max,1); Label6.Caption := IntToStr(life_max_Spieler.life_max); Label7.Caption := IntToStr(life_akt_Spieler); Label10.Caption := IntToStr(level_Spieler); end;
if fAnfang.RadioGroup2.ItemIndex = 0 then begin uNuetzlich.kreatur_zeichnen(fKampf.Canvas,'Kreaturen/Erdelement.Bmp',120,-280); Label4.Caption := 'Erdelement'; uNuetzlich.life_balken(fKampf.Canvas,life_max_Gegner.life_max,life_max_Gegner.life_max,2); Label9.Caption := IntToStr(level_Gegner); end;
Erledigt := True; end;
end; |
Funzt nicht, genau, wie wenn ich den Timer drin hab... :?
nn
Ja-Pa - Fr 30.12.05 13:50
nn1234 hat folgendes geschrieben: |
| Funzt nicht |
WAS funktioniert denn nicht? Fehlermeldung? Programm hängt? Schleife bricht vorzeitig ab?
Tipp: Einfach mal den Debugger drüber laufen lassen (im Einzelschritt ausführen -> mehrmals F7 drücken).
So kannst du die einzelnen Schritte genau nachvollziehen und siehst, wenn etwas nicht stimmt.
nn1234 - Fr 30.12.05 13:54
Fehlermeldung kommt keine, aber es werden keine Aktionen ausgeführt...
| Zitat: |
| Funzt nicht, genau, wie wenn ich den Timer drin hab... |
siehe weiter oben:
| Zitat: |
| ...macht er gar nichts mehr |
Ja-Pa - Fr 30.12.05 13:58
Meinst du mit gar nichts mehr, dass sich das Programm "aufhängt"?
Dann würd ich mal die Prozeduren im OnCreate-Ereignis (z.B. SetViewPortOrgEx) überprüfen... sonst müsste der Code IMHO funktionieren :?
nn1234 - Fr 30.12.05 14:06
Nein, die Aktionen, die im OnShow stehen, werden einfach nicht ausgefährt.
Narses - Fr 30.12.05 14:16
Moin!
Pack mal ein ShowMessage('Hallo'); mit rein, dann starten. Kommt was?
cu
Narses
nn1234 - Fr 30.12.05 17:30
Unerwarteter Weise ja. Bevor Form2 sichtbar ist, zeigt's mir 'Hallo'. Kann es also sein, das die Aktionen zwar ausgeführt werden, dies allerdings zu früh und dass man sie darum nicht ausgeführt sieht? Wenn ja, wie behebt man solch ein Problem?
DarkHunter - Fr 30.12.05 18:07
Welchen Itemindex haben die Radiogroups?
Schließlich machst du den kompletten Ablauf von den einzelnen Indexes abhängig.
Was willst du damit eigentlich bezwecken? Da diese Aktionen nur beim starten durchgeführt werden, hat der User doch gar keine Möglichkeit das zu ändern, oder sehe ich das falsch?
Daher frage ich mich welchen Sinn das macht die If-Abfrage zu machen, da der Itemindex doch Standartmäßig immer "0" ist, es sein denn es wurde von Programmierer anderes definiert.
nn1234 - Fr 30.12.05 19:07
Vom Grundaufbau läuft das Ganze so ab:
Auf Form1 sind Radiogroups mit denen der User jeweils eine Kreatur für sich und eine für den Gegner aussuchen kann. Da ich noch in der Testphase bin, habe ich zunächst eine Kreatur für den Spieler und eine für den Gegner erstellt. Es sollen natürlich weitere folgen, womit die if-Schleife begründet wäre (bis jetzt nur mitt Null, da erst eine Kreatur da ist - Schleife wird noch erweitert). Die ausgewählten Kreaturen sollen dann mit ihrem dazughörigen Level und der Lifeanzeige abgebildet sein, sobald das neue Formular sich öffnet. Das passiert nach klicken eine Buttons.
Soviel zum Aufbau. Da ich FormCreate für mein Problem nicht nutzen kann, wollte ich Timer einbauen, um die Kreaturen abzubilden. Das geht aber nicht. Genauso, wie das verwenden dieser Variablen Erledigt in FormShow.
Was kann ich noch versuchen?
Ich versteh das absolut nicht, da ich vorher eine ähnliche Prozedur in einem anderen Programm geschrieben hatte. Da brauchte ich nach den Methoden den Timer einfach auf Enable := False; stellen und da hat alles ordnungsgemäß funktioniert... :?:
nn1234 - Sa 31.12.05 02:39
So, hab heute früh viertel vor elf das Problem beschrieben. Nun ist es 13 1/2 Stunden und eine Lösung später... :D
Ich vermute mal, dass der Timer von mir zu schnell auf Enable:=False; gesetzt wurde - das Intervall zu klein war. Hab ich dieses verändert, hat sich aber nichts getan.
Der Fehler lag darin, dass die Eigenschaft Enable direkt nach dem Aufruf der davorigen Methode auf False gesetzt wurde. Somit hat der Timer praktisch keine Zeit, die Methode auszuführen. Methoden, die am Anfang des Timers aufgerufen werden, funktionieren ja (siehe ShowMessage).
Problembehebung:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19:
| procedure Form2.Timer1Timer(Sender: TObject);
procedure Pause(ms: Cardinal); var Stop,Timer: Cardinal; begin Timer := SetTimer(0, 0, ms, nil); Stop := GetTickCount + ms; repeat Application.HandleMessage; until Application.Terminated or (Integer(GetTickCount - Stop) >= 0); KillTimer(0, Timer); end;
begin Pause(500); Timer1.Enabled := False; end; |
So funktioniert's und ich kann beim Timer bleiben :roll: :lol:
Vielen Dank, für die zahlreichen Anregungen!
nn
Opa - Sa 31.12.05 09:07
Die Lösung mit den 500 mms Pause kann eigentlich nur falsch sein, sie macht nicht wirklich einen Sinn. Wenn dann sollte dort
Application.ProcessMessages oder
Repaint, entweder von der Form bzw. von einem Panel
ggf. auch Panel.DoubleBuffered := true
stehen.
Soll die Procedure Form2.Timer1Timer sofort ausgeführt werden kann man sie u.a. aus Create sofort aufrufen Form2.Timer1Timer(self) oder Form2.Timer1Timer(nil).
Ich denke das der Fehler in Application.HandleMessage steckt ich würde am Ende Application.ProcessMessages wählen.
Quelltext
1: 2: 3: 4: 5:
| begin {sämtliche Methoden, die der Timer ausführen soll} Application.ProcessMessages Timer1.Enabled := False; end; |
MSCH - Sa 31.12.05 09:37
grausam. tse tse
also
versuch's mal Damit
Delphi-Quelltext
1: 2:
| const wm_StartFlag = wm_Application + 1; |
in der Klassendeklaration
Delphi-Quelltext
1:
| procedure WMStartFlag(var Msg:TMessage);Message wm_StartFlag; |
in der OnCreate()-Methode
Delphi-Quelltext
1:
| postMessage(Self.handle, wm_StartFlag,0,0) |
die Funktion
Delphi-Quelltext
1: 2: 3: 4:
| [Klasse].WMStartFlag; begin end; |
Das Vorgehen ist simple, eine Nachricht wird beim Erstellen der form in die
Nachrichtenschleife eingesetzt und erst wenn der Rest abgearbeitet ist, folgt der Aufruf
der Funktion WMStartFlag().
Das funktioniert nur einmal und auch nur via PostMessage().
Vergiss den Kram mit Timer und Variablen.
grez
msch
nn1234 - So 01.01.06 13:26
Am Ende ist doch die einfachste Lösung, die beste. Hab jetzt einfach das zweite Formular nur mit Show statt ShowModal angezeigt. So kann ich den ganzen Timer Quatsch in die ButtonKlick Methode rein setzen, die das Formular auch anzeigt.
-Problem geklärt- :D
nn
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2026 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!