Entwickler-Ecke
Windows API - Schließbutton in der Titelzeile
Mathematiker - So 05.01.14 20:56
Titel: Schließbutton in der Titelzeile
Hallo,
bei dem einen oder anderen Programm möchte ich eine schnell laufende Animation erreichen und verzichte deshalb auf einen Timer.
Konkret läuft in einer Methode die Animation in der Form:
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:
| procedure animation(sender:tobject); begin if animationlaeuft then begin animationlaeuft:=false; exit; end else begin animationlaeuft:=true; repeat ... application.processmessages; ... until not animationlaeuft; end; end;
procedure schliessen(sender:tobject); begin if animationlaeuft then animationlaeuft:=false; close; end; |
Sobald die Variable animationlaeuft auf false gesetzt wird (evtl. Buttonklick) stoppt die Animation. Das funktioniert auch perfekt mit der Methode schliessen, die dann auch das Programm beendet.
Nun mein Problem: Wie kann ich erreichen, dass der Standard-Schließbutton in der Titelzeile ebenfalls die Animation stoppt und das Programm beendet?
Meine Versuche, in die Ereignisse Onclose oder Onclosequery die zwei Zeilen von schliessen einzutragen, funktionieren nicht. Während der Animation wird scheinbar keines dieser Ereignisse durch den Schließbutton ausgelöst. Ich kann soviel ich will auf den Schließbutton drücken, es passiert nichts. Beende ich mit der Methode schliessen ist dagegen alles in Ordnung.
Welches Ereignis wird denn ausgelöst, wenn ich auf den Schließbutton drücke?
Ich bin mir nicht ganz sicher, aber kann es sein, dass es unter Vista und XP noch funktionierte? Irgendwie komisch.
Beste Grüße
Mathematiker
Nachtrag: Hat sich eigentlich erledigt. Ich habe es hingekriegt mit
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| procedure TForm.WndProc(var msg:TMessage); begin case Msg.Msg of WM_CLOSE: begin if sofortabbruch=false then sofortabbruch:=true; close; end Else inherited; end; end; |
Aber vielleicht hat jemand ja noch eine bessere Idee.
Delphi-Laie - So 05.01.14 21:18
Ich kann da leider nur aus bescheidenen Erfahrungen schöpfen.
Mit Application.Processmessages nimmt ein auch im VCL-Thread vollbeschäftigtes Formularprogramm Eingaben wahr und löst die entsprechende(n) Ereignisbehandlungsroutinen aus. Dort kann man irgendeine Variable umschalten. Diese Variable wird in der eigentlichen Berechnung (nahezu) ständig ausgewertet - so eine Art Polling (kein Eingabe-, sondern ein Variablenpolling). So läuft es in meinem "Sortierkino".
Oder man agiert mit einem Extrathread, aber das ist aufwendiger (synchronize bei Formularausgaben). Den kann man sich selbst separat beenden lassen oder von außen gewaltsam abschießen (s. mein unfertiger "Langzahlentaschenrechner"), aber das ist unelegant.
Edit: Da waren wir wohl im Geschwindigkeitswettstreit, ohne daß wir es wußten.
Edit 2: Beim X-Druck werden OnClose und OnCloseQuery ausgelöst, die Reihenfolge weiß ich jetzt aber nicht (einfach mal mit z.B. Messagesboxen oder verschiedenfrequenten Pieptösnen ausprobieren).
mandras - So 05.01.14 22:13
Wenn Du im OnClick einer Schaltfläche CLOSE aufrufst,
wird über Zwischenwege Application.Terminate aufgerufen, das sendet an Windows das PostQuitMessage, die Anwendung wird von Windows beendet.
Drückst Du die Schaltfläche "Schließen" oben rechts im Fenstertitel passiert das nicht.
Zwar merkt Delphi vor, daß die Anwendung geschlossen werden soll, bleibt aber in der repeat-Schleife mit dem Processmessages "kleben".
Abhilfe:
Delphi-Quelltext
1:
| until not animationlaeuft or Application.Terminated; |
Mathematiker - So 05.01.14 22:26
Hallo,
Delphi-Laie hat folgendes geschrieben : |
Beim X-Druck werden OnClose und OnCloseQuery ausgelöst, die Reihenfolge weiß ich jetzt aber nicht (einfach mal mit z.B. Messagesboxen oder verschiedenfrequenten Pieptösnen ausprobieren). |
Danke für den Tipp. Nur leider funktioniert es nicht.
Läuft die Animation, so bewirkt das Klicken auf X kein "Hineinspringen" in die Methoden von beiden Ereignissen.
mandras hat folgendes geschrieben : |
Wenn Du im OnClick einer Schaltfläche CLOSE aufrufst,
wird über Zwischenwege Application.Terminate aufgerufen, das sendet an Windows das PostQuitMessage, die Anwendung wird von Windows beendet. |
Ebenfalls Danke. Das Problem ist, dass ich auch eine Idee suche (
habe mich im 1.Beitrag nicht ganz konkret ausgedrückt), wenn nur ein Formular geschlossen werden soll und nicht die ganze Anwendung. Dann geht es so leider nicht.
Beste Grüße
Mathematiker
Nachtrag: Sehr ärgerlich. Die Idee mit
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| procedure TForm.WndProc(var msg:TMessage); begin case Msg.Msg of WM_CLOSE: begin if sofortabbruch=false then sofortabbruch:=true; close; end Else inherited; end; end; |
funktioniert in einer anderen Anwendung nicht. Dagegen bekomme ich die Meldung, dass mein WndProc die virtuelle Methode von TCustomform verbirgt. :nixweiss:
mandras - So 05.01.14 23:01
Hm..
1) Kann es sein, daß Du bei der Deklaration der WndProc das override vergessen hast?
2) Ich habe (allerdings mit D6) eine Anwendung mit 2 Fenstern erstellt.
Auf dem Hauptfenster ein Button, der nur das 2. Fenster anzeigt.
2. Fenster: Ein Button der die "repeat ... processmessages" auslöst.
Wenn ich "Close" im Fenstertitel klicke passiert folgendes:
Fenster 2 wird geschlossen, Fenster 1 läßt sich nicht mehr über sein "Close" im Titel schließen.
Soweit logisch, Fenster 2 ist unsichtbar, die Schleife mit dem Repeat aber noch aktiv.
! Bei dieser Konstellation kann ich aber in der Repeat-Schleife prüfen, ob das Form noch auf "visible" steht. -> Wenn nein: Schleife beenden.
! Wenn das Form mit der processmessages-Schleife nicht das Hauptformular der Anwendung ist, werden hier wie erwartet die OnClose-Ereignisse ausgelöst über die Close-Fläche im Titel.
Mathematiker - So 05.01.14 23:08
Hallo,
mandras hat folgendes geschrieben : |
1) Kann es sein, daß Du bei der Deklaration der WndProc das override vergessen hast?
|
Genau das ist es und wieder typisch für mich. :autsch:
Besten Dank, denn jetzt funktioniert es mit WndProc einwandfrei.
Beste Grüße
Mathematiker
Delphi-Laie - So 05.01.14 23:19
mandras hat folgendes geschrieben : |
Wenn ich "Close" im Fenstertitel klicke passiert folgendes:
Fenster 2 wird geschlossen, Fenster 1 läßt sich nicht mehr über sein "Close" im Titel schließen.
Soweit logisch, Fenster 2 ist unsichtbar, die Schleife mit dem Repeat aber noch aktiv. |
Das ist tückisch und war mir zugegenermaßen auch nicht (mehr) bewußt. Bei Programmen, die mit dem Visual-Studio erstellt wurden, beendet der X-Druck das Formular tatsächlich, auch untergeordnete Formulare (zumindest die mit C# erstellten, soweit ich mich recht entsinne). Greift man danach - z.B. in guter alter Delphi-Gewohnheit, es wieder sichtbar zu machen - erneut darauf zu, kommt natürlich irgendein Programmfehler (Exzeption o.ä.).
Unabhängig vom Formular kann man natürlich die Variable in der repeat-until-Schleife ständig abfragen und natürlich ggf. die Schleife beenden.
Mathematiker - Mo 06.01.14 20:32
Hallo,
ich muss noch einmal auf das Thema zurückkommen. Durch den Hinweis von
mandras auf ein geschlossenes Fenster mit noch laufender Schleife bin ich vorsichtig geworden.
Daher habe ich Folgendes versucht:
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:
| procedure form.animation(sender:tobject); begin if animationlaeuft then animationlaeuft:=false else begin animationlaeuft:=true; schliessbar:=false; repeat ... application.processmessages; ... until not animationlaeuft; schliessbar:=true; end; end; procedure form.WndProc(var msg:TMessage); begin case Msg.Msg of WM_CLOSE: begin if animationlaeuft then animationlaeuft:=false; if schliessbar then close; end Else inherited; end; end; |
Erwartet habe ich nun, dass bei Klick auf das X (Schließen) die Animation gestoppt wird und das Fenster sich schließt. Und natürlich schließt es sich nicht!
D.h. also bei der ursprünglichen Variante
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| procedure form.WndProc(var msg:TMessage); begin case Msg.Msg of WM_CLOSE: begin if animationlaeuft then animationlaeuft:=false; close; end Else inherited; end; end; |
schließt sich das Fenster und die Schleife läuft wohl noch weiter; oder wird geschlossen, wenn das Fenster nicht mehr existiert (geht ja wohl nicht), da ich bei der Rückkehr zum aufrufenden Formular form.release aufrufe.
Dann müsste es doch aber irgendwelche Probleme geben, von harmlosen Fehlermeldungen bis gravierenden Programmabstürzen.
Aber nichts passiert. Ich habe heute auf meinem "schnellen" PC unter Win 8.1 getestet, auf einem etwas langsameren mit Win 7 (64) und auf einer "lahmen Ente" mit XP.
In allen Fällen gab es keine Schwierigkeiten, wenn ich sofort das close ohne den Test auf schliessbar aufrufe. Mit dem Test bleibt das Fenster offen.
Das verstehe ich nun nicht mehr.
Kann ich davon ausgehenden, dass die Methode WndProc in der Form ohne den Sicherheitstest, ob die Animation beendet ist, funktioniert? Irgendwie werde ich das Gefühl nicht los, dass da noch ein "böser" Fehler lauert, der zuschlägt, wenn ich es nicht erwarte.
Beste Grüße
Mathematiker
Delete - Mo 06.01.14 22:37
Wieso nicht einfach in OnCloseQuery vor der Zeile CanClose := True die Variable animationlaeuft auf False setzen?
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10:
| Procedure TFormMain.FormCloseQuery(Sender: TObject; var CanClose: Boolean); begin CanClose := False;
AnimationLaeuft := False; SonstigenKramErledigen; AlleKlassenFreigeben;
CanClose := True; end; |
OnCloseQuery wird beim Schließen des Formulars aufgerufen. Ist das Forumlar das Hauptformular, wird das Programm beendet.
Mathematiker - Mo 06.01.14 22:50
Hallo,
Danke für die Antwort.
Perlsau hat folgendes geschrieben : |
Wieso nicht einfach in OnCloseQuery vor der Zeile CanClose := True die Variable animationlaeuft auf False setzen? ...
OnCloseQuery wird beim Schließen des Formulars aufgerufen. Ist das Forumlar das Hauptformular, wird das Programm beendet. |
Das habe ich schon ausprobiert; und jetzt noch einmal. Und genau dort liegt mein Problem.
Während der Animation kann ich noch so oft auf den X-Button klicken. OnCloseQuery wird scheinbar nicht ausgelöst, denn das Programm springt einfach nicht in die Methode hinein; obwohl es funktionieren müsste.
Allerdings funktioniert es sofort, wenn es um das Hauptformular geht, nur eben nicht bei weiteren Formularen.
Ich weiß im Moment nicht weiter. Wahrscheinlich habe ich irgendwo ein anderes Problem.
Beste Grüße
Mathematiker
Delete - Mo 06.01.14 22:57
Mathematiker hat folgendes geschrieben : |
Das habe ich schon ausprobiert; und jetzt noch einmal. Und genau dort liegt mein Problem. Während der Animation kann ich noch so oft auf den X-Button klicken. OnCloseQuery wird scheinbar nicht ausgelöst, denn das Programm springt einfach nicht in die Methode hinein; obwohl es funktionieren müsste. Ich weiß im Moment nicht weiter. Wahrscheinlich habe ich irgendwo ein anderes Problem. |
Wenn du die Animation nicht als eigenen Thread laufen läßt, kommt dein "Programmzeiger" ja von der Animations-Procedure gar nicht mehr zurück, sobald diese gestartet wurde ... In der Message-Queue steht zwar schon der Klick auf das Titelzeilen-X und wartet darauf, endlich dranzukommen, aber er kann erst abgearbeitet, wenn die zuvor aufgerufene Procedure beendet ist.
Mathematiker - Mo 06.01.14 23:06
Hallo,
Perlsau hat folgendes geschrieben : |
Wenn du die Animation nicht als eigenen Thread laufen läßt, kommt dein "Programmzeiger" ja von der Animations-Procedure gar nicht mehr zurück, sobald diese gestartet wurde ... |
Danke für den Hinweis.
Aber, deshalb wird ja in der Animation application.processmessages gerufen. Und wie weiter oben gesagt, über WndProc funktioniert es ja, aber mit dem für mich blöden Beigeschmack, dass ich der ganzen Sache nicht vertraue.
Ich vermute, dass es mit FormCloseQuery nicht so wie erwartet will, hat vielleicht etwas mit meinem nicht gerade frischem Delphi 5 und der Tatsache, dass das 2.Fenster modal ist, zu tun.
Beste Grüße
Mathematiker
mandras - Di 07.01.14 00:21
Ich habe (siehe oben) mit D6 getestet.
Meine Erkenntnisse waren:
Wenn das Form das MainForm ist klappt das ganze nicht (es wird zwar Application.Terminated gesetzt, da das Programm aber in der Repeat-Schleife "hängt" hat dies keine Auswirkungen. OnClose und OnCloseQuery wird nicht aufgerufen wenn man den "Close"-Button der Titelleiste betätigt. Über einen Extra-Button der die "Close"-Methode des Forms aufruft funktioniert es.
Wieder Close-Button der Titelleiste: Wenn das Form _nicht_ das Main Form ist wird es zwar geschlossen, die repeat-Schleife aber nicht beendet.
! Wenn das Form nicht Main Form ist, ist es egal, ob es modal ist oder nicht. Geschlossen wird es.
Der Code von Mathematiker von 19:32 ist auch nicht der Weisheit letzter Schluß:
Delphi-Quelltext
1: 2:
| if animationlaeuft then animationlaeuft:=false; if schliessbar then close; |
Das kann nicht funktionieren.
Schließbar ist vorher false. Es wird erst auf true gesetzt in .animation.
.animation wird aber erst NACH diesem Code aufgerufen. Daher wird Schließbar hier immer false sein, die Methode Close daher nicht aufgerufen.
Die ursprüngliche Variante ist m.E. nach zielführend. Das explizite Aufrufen von TForm.Close klappt immer. Da wird dann auch korrekt unterschieden, ob das Form nur geschlossen (nicht Main Form) oder das Programm beendet werden soll.
Delphi-Laie - Di 07.01.14 00:21
Allzu qualifiziert kann ich zu dieser Diskussion leider nichts beisteuern, aber hier:
Mathematiker hat folgendes geschrieben : |
Ich vermute, dass es mit FormCloseQuery nicht so wie erwartet will, hat vielleicht etwas mit meinem nicht gerade frischem Delphi 5 und der Tatsache, dass das 2.Fenster modal ist, zu tun. |
wage ich leichte Entwarnung zu geben: Schon Delphi 1, spätestens Delphi 2 hatten (ziemlich) ausgereifte Ereignisbehandlungen. Da wurde doch n.m.W. nichts mehr "korrigiert", es kamen eher / höchstens weitere Dinge hinzu.
Wie schon geschrieben, mein Sortierkino ist auch im laufenden Betrieb - dank application.processmessages - abbrechnenbar, und das kann ich in einer Version schon ab Delphi 2.0 compilieren.
Delphi-Laie - Di 07.01.14 00:24
Mathematiker hat folgendes geschrieben : |
Während der Animation kann ich noch so oft auf den X-Button klicken. OnCloseQuery wird scheinbar nicht ausgelöst, denn das Programm springt einfach nicht in die Methode hinein; obwohl es funktionieren müsste. |
Scheinbar oder tatsächlich?
Ich pflege mir immer mit einfachen Pieptönen in solchen Fällen zu helfen.
Wenn Du in OnClose und/oder OnCloseQuery einen Breakpoint setzt, wird dann ddas Program beim X-Druck an der Stelle unterbrochen oder nicht? Auch der Breakpoint kann von der IDE nicht ignoriert werden, wenn er angesprungen wird.
Mathematiker - Di 07.01.14 00:32
Hallo,
Delphi-Laie hat folgendes geschrieben : |
Scheinbar oder tatsächlich? ... Wenn Du in OnClose und/oder OnCloseQuery einen Breakpoint setzt, wird dann ddas Program beim X-Druck an der Stelle unterbrochen oder nicht? |
Tatsächlich!
Den Breakpoint habe ich gesetzt und nichts passiert.
Ich habe ein älteres Programm etwas verändert und hänge es einmal 'ran. Die Plasmadarstellung ist in einem modalen Fenster, so wie meine eigentliche Animation.
Startet man nach dem Zeichnen die Farbrotation hat der X-Button "keine Wirkung" mehr.
Ich danke allen für die Mühe und Hilfe und es eilt nicht.
Ich muss jetzt erst einmal ins Bett. Morgen früh 5.30 Uhr ist die Nacht leider vorbei.
Beste Grüße
Mathematiker
Delete - Di 07.01.14 12:17
Was mir als Erstes auffällt:
Du arbeitest so gerne mit Konstanten, die in Wirklichkeit KEINE sind.
Ständig weist Du den "Konstanten" andere Werte zu!
Delphi-Laie - Di 07.01.14 13:37
Das ist in der Tat merkwürdig.
Um das Problem zu vereinfachen (neudeutsch: "herunterzubrechen"), erstellte ich mal ein kleines Projekt, absichtlich mit Delphi 2. Es funktioniert so, wie es m.E. funktionieren sollte. Die beiden Pieptöne in aufsteigender Frequenz beim X-Druck sollen einfach das Durchlaufen von OnCloseQuery und OnClose (in dieser Reihenfolge) anzeigen.
Drei Sachen sind jedoch bemerkenswert:
1. Obwohl erst in OnCloseQuery (oder in OnClose, funktioniert auch dort) die Abbruchbedingung der Schleife "freigeschaltet" wird, die Schleife also mindestens noch einmal angesprungen und damit das Abbrechen unterbrochen wird, funktioniert dennoch auch das Schließen des (jeweiligen) Formulares oder gar das Beenden des Programmes. Das Schließen ist also ein wahrlich komplexer Prozeß, der unterbrech- und fortsetzbar ist, wobei OnClose(Query) jeweils nur einmal durchlaufen werden.
2. Das Hauptformular und damit das Programm können nicht beendet werden, wenn die Schleife im unter- bzw. zugeordneten Formular noch läuft. Eine laufende Schleife verhindert also das Programmende.
3. Wird nach 2. das untergeordnete Formular und mit ihm seine Schleife beendet, beendet sich das Programm ohne erneuten X-Druck auf das Hauptformular. Das Programm merkt sich demnach auf mysteriöse Weise, daß es schon einmal (erfolglos) zu beenden versucht wurde.
Derlei Tücken wie hier das Nichtanspringen der OnClose-Ereignisbehandlungsprozeduren sind mir in prinzipieller Form wohlbekannt. Es gibt für jemanden wie mich, der wenig Ahnung hat, zwei Möglichkeiten, der Ursache auf die Spur zu kommen (wobei ich die erstere wegen tendenziell geringerem Aufwand bevorzuge). Entweder das problembehaftete Programm soweit vereinfachen ("herunterbrechen"), daß es einen solch simplen Charakter bekommt wie meines (zwischendurch immer wieder die Löschschaktionen dokumentieren, um die Ursache einzukreisen) oder ein simples Programm immer mehr mit Leben erfüllen (hier sind ebenfalls die Dokumentation, was hinzugefügt wird, wichtig).
Postscriptum: Den Wert boolescher Variablen über den = -Operator abzufragen, ist unelegant. Statt =false besser if not ...
Delete - Di 07.01.14 13:50
Ich habe mal ein paar Änderungen gemacht:
- procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean); // entfällt ! da ohne Wirkung
- Button Exit1 eingefügt
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:
| var Form1: TForm1; zeichnenaktiv:boolean; rotation:boolean; waagerecht:boolean; stopp : Boolean;
implementation
{$R *.DFM}
procedure TForm1.FormCreate(Sender: TObject); begin zeichnenaktiv:= false; rotation:= false; waagerecht:= false; stopp:=false; end;
procedure TForm1.Exit1Click(Sender: TObject); begin stopp:=true; Form1.Close; end;
procedure TForm1.Button2Click(Sender: TObject); var i,j:integer; k,index : integer; begin if not rotation then begin cyclestart:=0; cb1.enabled:=false; button2.caption:='Stop'; rotation:=true; repeat if stopp=true then exit; cyclestart:=cyclestart+1; ... |
WasWeißDennIch - Di 07.01.14 14:14
Lass doch bitte das "Form1" im Exit1Click weg. Und Vergleiche auf true müssen nicht immer das richtige Ergebnis liefern, daher "=true" im Button2Click auch mit streichen.
Delete - Di 07.01.14 14:24
Close oder Form1.Close
Was spielt das für eine Rolle?
Wenn Du schon was zu meckern hast, dann begründe es!
WasWeißDennIch - Di 07.01.14 14:37
Delphi-Quelltext
1: 2: 3: 4: 5: 6:
| var Form1: TForm1;
procedure TForm1.MachZu; Form1.Close; end; |
Das funktioniert genau solange, wie eine Instanz von TForm1 in der globalen Variablen Form1 hinterlegt ist. Hier würde es knallen:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13:
| var Form1: TForm1; FormMain: TForm1;
...
FormMain := TForm1.Create(Applicaton);
...
procedure TForm1.MachZu; Form1.Close; end; |
Hier gibt es keine Instanz von TForm1 in Form1, sondern in FormMain. Und das ist der entscheidende Unterschied. Und selbst wenn es beide Instanzen gibt, wird immer auf dieselbe zugegriffen, das ist mit ziemlicher Sicherheit so nicht beabsichtigt.
Mathematiker - Di 07.01.14 14:51
Hallo,
Danke für die Hinweise.
Einen Ausstiegsschalter in der beschriebenen Form hatte ich schon eingefügt und der funktionierte auch fehlerfrei.
Scheinbar gibt es nur die eine Möglichkeit, während einer nicht timergesteuerten Animation in einem modularen Fenster, den X-Button der Titelzeile aufzurufen (und darum geht es mir ja). Also habe ich bei jeder derartigen Animation wieder
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| procedure TForm.WndProc(var msg:TMessage); begin case Msg.Msg of WM_CLOSE: begin if not sofortabbruch then sofortabbruch:=true; close; end Else inherited; end; end; |
eingefügt und massiv getestet. FastMM zugeschaltet und immer wieder an den unmöglichsten Stellen während der Animation auf X gedrückt, ergab bei keiner der Routinen Probleme. Bisher jedenfalls nicht.
Mal sehen, ob in der nächsten Zeit auf irgendeinem Rechner doch Schwierigkeiten auftreten. Wenn ja, ist es ärgerlich, aber es gibt ja keine fehlerfreie Software und von mir(!) schon gar nicht. :wink:
Außerdem habe ich angefangen, einige Animationen doch mit einem Timer zu steuern. Es wird etwas langsamer, aber bei den heutigen Rechnern immer noch schnell genug.
Beste Grüße und Danke für die Hilfe
Mathematiker
Delphi-Laie - Di 07.01.14 14:52
Wird das Formular 1 genau wie Formular 2 erzeugt (in program pplasma):
Delphi-Quelltext
1: 2: 3: 4: 5:
| Application.Initialize; Application.Title := 'Plasma'; Application.CreateForm(TForm2, Form2); Application.CreateForm(TForm1, Form1); Application.Run; |
und wird das Formular 1 in unit plasmaaufrufen so aufgerufen:
Delphi-Quelltext
1: 2: 3: 4:
| procedure TForm2.Button1Click(Sender: TObject); begin form1.show end; |
, dann läßt sich das Formular 1 auch einfach und sauber beenden (inkl. Schleifenabbruch). Heureka?!
Delphi-Laie - Di 07.01.14 14:59
Mathematiker hat folgendes geschrieben : |
Außerdem habe ich angefangen, einige Animationen doch mit einem Timer zu steuern. Es wird etwas langsamer, aber bei den heutigen Rechnern immer noch schnell genug. |
Zwar steht es mir nicht zu, Dich zu bevormunden, Mathematiker, aber wenn ich etwas dazu loslassen darf: Bitte nicht. Das ist unelegant. Gerade hohe Rechengeschwindigkeit begründet oft erst den eigentlichen Augenschmaus. Tendenziell, solange wir mit Computern zu tun hattenn, waren diese bisher immer doch eher zu langsam als zu schnell. Auch Deine Farbrotation wird umso beeindruckender, je schneller sie abläuft (natürlich nur bis zu einer gewissen Grenze). Insofern wäre es schade, ein wertvolles Potential zu verschenken.
Außerdem haben Timer
gerade nicht(s) mit der Rechengeschwindigkeit zu tun, schon gar nicht bei "heutigen Rechnern", die "immer noch schnell genug" sind. Höchstens umgekehrt wird ein Schuh daraus: Wenn ein Computer zu langsam ist, kann es sein, daß der Timer nicht mehr hinterherkommt und auslösende Ereignisse ausgelassen werden ("unter den Tisch fallen").
jaenicke - Di 07.01.14 15:25
Mathematiker hat folgendes geschrieben : |
Ich habe ein älteres Programm etwas verändert und hänge es einmal 'ran. Die Plasmadarstellung ist in einem modalen Fenster, so wie meine eigentliche Animation.
Startet man nach dem Zeichnen die Farbrotation hat der X-Button "keine Wirkung" mehr. |
Lösen lässt sich das sehr einfach. Du musst die Abbruchbedingung der Schleife so schreiben:
Delphi-Quelltext
1:
| until not rotation or (ModalResult <> mrNone); |
Hintergrund ist, dass du das aus einem ShowModal aufrufst und dementsprechend in einer neuen Nachrichtenwarteschlange.
Dein Assemblercode in der Funktion farbmitte ist jedenfalls nicht korrekt. Richtig (ohne genauer geschaut zu haben was der macht):
Delphi-Quelltext
1: 2: 3: 4: 5: 6:
| cmp eax, 0 jz @null jmp @end @null: mov eax, 1 @end: nop end; |
Hintergrund:
Das ret kommt beim end automatisch. Dadurch, dass du noch ein eigenes einfügst, zerschießt du dir den Stack, und zwar gründlich...
Delete - Di 07.01.14 15:47
Ich habe jetzt DIE Lösung, die auch unseren Mathematiker zufriedenstellen wird:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22:
| ... private FCanClose : Boolean; procedure WMNCLBUTTONDOWN(var msg: TMessage); message WM_NCLBUTTONDOWN;
... procedure TForm1.WMNCLBUTTONDOWN(var msg: TMessage); begin if msg.wParam = HTCLOSE then BEGIN Windows.Beep(800,50); FCanClose:=true; Close; END; inherited; end; ...
repeat if FCanClose = True then exit; ... |
Mathematiker - Di 07.01.14 15:55
Hallo,
hathor hat folgendes geschrieben : |
Ich habe jetzt DIE Lösung, die auch unseren Mathematiker zufriedenstellen wird: |
Danke, werde ich sofort ausprobieren.
Aber ...
jaenicke hat folgendes geschrieben : |
Lösen lässt sich das sehr einfach. Du musst die Abbruchbedingung der Schleife so schreiben: Delphi-Quelltext 1:
| until not rotation or (ModalResult <> mrNone); | Hintergrund ist, dass du das aus einem ShowModal aufrufst und dementsprechend in einer neuen Nachrichtenwarteschlange. |
"Sehr einfach"? Ja, es ist sehr einfach, aber auf so etwas wäre ich nie gekommen. Es funktioniert absolut perfekt.
Besten Dank und tiefe Verbeugung :flehan: .
jaenicke hat folgendes geschrieben : |
Dein Assemblercode in der Funktion farbmitte ist jedenfalls nicht korrekt. ... |
Super. Bei einem Problem bekomme ich gleich die Lösungen für zwei Sachen.
Nochmals vielen Dank.
Beste Grüße
Mathematiker
Delphi-Laie - Di 07.01.14 15:56
Kann nicht dieser redundante und hinsichtlich binärer Interna genaugenommen sogar falsche (weil fehlerträchtige) Vergleich boolescher Variablen mit "true" bzw. "false" endlich mal aufhören?
Mathematiker - Di 07.01.14 16:28
Hallo,
Delphi-Laie hat folgendes geschrieben : |
Kann nicht dieser redundante und hinsichtlich binärer Interna genaugenommen sogar falsche (weil fehlerträchtige) Vergleich boolescher Variablen mit "true" bzw. "false" endlich mal aufhören? |
Ich muss
hathor in Schutz nehmen.
Er hat nur das gemacht, was ich schon begonnen hatte. Der Vergleich auf "true" usw. stammt aus meinem Beispielprogramm. :autsch:
Beste Grüße
Mathematiker
WasWeißDennIch - Di 07.01.14 16:32
Dann schäme er sich, und ihm wird vergeben werden :zwinker:
Delphi-Laie - Di 07.01.14 17:35
Nunja, ich bin mir sicher, daß das Helferlein es besser wußte und nehme zu seinem Gunsten an, daß nur Flüchtigkeit die Ursache war. Allerdings wurde das in dieser Diskussion auch schon vorher moniert.
Mathematiker hat folgendes geschrieben : |
Der Vergleich auf "true" usw. stammt aus meinem Beispielprogramm. :autsch: |
Vermutlich aber letztlich aus Deinem übergeordneten Programm. Programmierstile schleifen sich über Jahre ein und verfestigen sich, man schleppt einiges ewig mit sich umher - sei es mental, sei es in Form so mancher Quelltexte.
Auch die In-/Dekrementierung integrer Variablen geht übrigens eleganter als mit den Rechenoperationen. Allerdings soll der Compiler das ohnehin erkennen und optimieren.
Warum Dein (scheinbar unbeendbares) Fenster, das uns so sehr beschäftigte, modal sein soll, erschließt sich mir nicht. Klar, es wird erst zur Laufzeit (besser: bei Bedarf) erzeugt, aber welchen Vorteil hat das? Speicherbedarfsreduktion? Konsequenterweise sollte es dann beim X-Druck auch zur Laufzeit "zerstört" werden.
jaenicke - Di 07.01.14 18:21
Delphi-Laie hat folgendes geschrieben : |
Warum Dein (scheinbar unbeendbares) Fenster, das uns so sehr beschäftigte, modal sein soll, erschließt sich mir nicht. Klar, es wird erst zur Laufzeit (besser: bei Bedarf) erzeugt, aber welchen Vorteil hat das? |
Schnellerer Start? Bei vielen Formularen dauert der Start sonst ewig, vom Speicherverbrauch ganz abgesehen.
Und modal, damit man an das aufrufende Fenster derweil nicht herankommt, dafür ist modal ja da.
Delete - Di 07.01.14 18:22
Wer sich ausgerechnet auf diese Seite bezieht, sollte mal das Gehirn einschalten!
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15:
| function GaaanzFieseAPIFunktion: Boolean; asm mov eax, -$01 end;
BoolToStr(GaaanzFieseAPIFunktion)); Form1.Color:= Integer(GaaanzFieseAPIFunktion);
var b := Boolean; |
WasWeißDennIch - Di 07.01.14 18:32
Du weißt schon, dass Niveau keine Handcreme ist?
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!