![]() |
Delphi-Version: 2005
Schleifenabbruch durch Esc Taste...
Hallo,
in der CodeLib auf Delphi Praxis gibt es die Beschreibung eines Schleifenabbruchs per Tastaturdruck mit Messagedialog Abfrage: ![]()
Delphi-Quellcode:
Beim Tastendruck wird das Hochzählen der Variablen i sofort gestoppt, aber der Messagedialog in der Funktion EscPressed wird erst 7 - 12 Sekunden später angezeigt.
procedure TForm1.Button1Click(Sender: TObject);
var i : Integer; begin ResetEscPressed; for i := 0 to 10000000 do begin Caption := inttostr(i); if EscPressed('Schleife abbrechen ?') then Break; end; end; Kann man da irgendwie was machen, dass der Dialog nahezu zeitgleich angezeigt wird? |
AW: Schleifenabbruch durch Esc Taste...
Zitat:
Zitat:
Und nicht die ESC-Taste zu lange drücken. :warn: -> Wenn Taste gedrückt, dann zeige den Dialog an und frag nach, ob wirklich abgebrochen werden soll. |
AW: Schleifenabbruch durch Esc Taste...
Zitat:
Delphi-Quellcode:
Also ich drücke den Button, die Schleife wird ausgeführt und im Form1.Caption wird das Hochzählen der Schleife angezeigt. Wenn ich jetzt ESC drücke, hört das Hochzählen sofort auf, aber der 'Schleife abbrechen' Dialog wird erst nach weiteren ~7 Sekunden angezeigt. Merkwürdig... Liegt es an Windows 7 64bit?Unit1 procedure TForm1.Button1Click(Sender: TObject); var i : Integer; begin ResetEscPressed; for i := 0 to 10000000 do begin Caption := inttostr(i); if EscPressed('Schleife abbrechen ?') then break; end; end; ... ... ... unit Tastendruck; interface uses Windows, Dialogs, Controls; function EscPressed(const Msg:string):Boolean; procedure ResetEscPressed; implementation function EscPressed(const Msg:string):Boolean; begin // Aus der WinAPI-Doku zu GetAsyncKeyState: // if the function succeeds, the return value specifies whether the key was pressed // since the last call to GetAsyncKeyState, and whether the key is currently up or down. // If the most significant bit is set, the key is down, and if the least significant bit is set, // the key was pressed after the previous call to GetAsyncKeyState. // The return value is zero if a window in another thread or process currently has the keyboard focus Result := ((GetAsyncKeyState(VK_ESCAPE) and $8001) <> 0) or ((GetAsyncKeyState(VK_PAUSE) and $8001) <> 0); if Result then begin Result := (MessageDlg(Msg, mtConfirmation, [mbYes,mbNo], 0) = mrYes); end; end; // muss vor dem Benutzen von EscPressed() aufgerufen werden procedure ResetEscPressed; begin GetAsyncKeyState(VK_ESCAPE); GetAsyncKeyState(VK_PAUSE); end; Während der 7 Sekunden geht am Rechner nichts anderes mehr. |
AW: Schleifenabbruch durch Esc Taste...
Wenn man sowieso IMMER abbrechen will, kann man sich den Dialog sparen.
Delphi-Quellcode:
function EscPressed(const Msg:string):Boolean;
begin Result := ((GetAsyncKeyState(VK_ESCAPE) and $8001) <> 0) or ((GetAsyncKeyState(VK_PAUSE) and $8001) <> 0); if Result then Result := TRUE; end; |
AW: Schleifenabbruch durch Esc Taste...
Zitat:
|
AW: Schleifenabbruch durch Esc Taste...
Klingt so, als wenn im Hintergrund die Schleife noch laufen und das Formular blockieren würde. Entweder man ruft in der Schleife Application.ProcessMessages auf oder man lagert das alles in einen Thread au.
|
AW: Schleifenabbruch durch Esc Taste...
Zitat:
Delphi-Quellcode:
Application.ProcessMessages bringt keine Änderung.
procedure TForm1.Button1Click(Sender: TObject);
var i : Integer; begin ResetEscPressed; for i := 0 to 10000000 do begin Application.ProcessMessages; Caption := inttostr(i); if EscPressed('Schleife abbrechen ?') then break; end; //For Label1.Caption:= 'stop'; end; //proc Beim Klick auf ESC zeigt das Label sofort 'Stop' an, die Schleife wird also sofort verlassen. Es muss einen anderen Grund geben. Gibt es eine andere Möglichkeit als GetAsyncKeyState? |
AW: Schleifenabbruch durch Esc Taste...
Keine Ahnung, was bei dir los ist, aber bei mir funktioniert dein Code. Ich würde in jedem Fall in die Schleife ein Sleep einbauen, damit andere Threads und Prozesse Zeit bekommen und dein Thread nicht die CPU voll auslastet. Ein
Delphi-Quellcode:
reicht da schon aus. Warum überhaupt eine for-Schleife mit einem hohen Zahlenwert als Abbruchbedingung statt einer while- oder repeat-until-Schleife?
Sleep(1);
MfG Dalai |
AW: Schleifenabbruch durch Esc Taste...
Zitat:
das Sleep(1) sorgt tatsächlich dafür, dass ich nach dem Klick auf ESC das Formular schließen kann. Ich habe das Sleep einfach mal so eingefügt:
Delphi-Quellcode:
Was ich gern verstehen würde, warum das so funktioniert, denn:
procedure TForm1.Button1Click(Sender: TObject);
var i : Integer; begin ResetEscPressed; for i := 0 to 10000000 do begin Application.ProcessMessages; Caption := inttostr(i); Sleep(1); //<- Sleep in der Schleife if EscPressed('Schleife abbrechen ?') then break; end; //For Label1.Caption:= 'stop'; Application.ProcessMessages; Button1.Enabled:=false; end; //proc Denn auch ohne Sleep zeigt das Label1 sofort 'Stop' an,wenn ich ESC drücke, das heißt doch, dass die Schleife auch verlassen ist. Warum brauche ich jetzt das Sleep um das Form schließen zu können? Was passiert da noch im Hintergrund? Und ich wäre jetzt nicht darauf gekommen da ein Sleep einzubauen. Und warum nun eine 4Kern CPU von einer Form.exe total eingenommen wird, wenn da ein GetAsyncKeyState(VK_ESCAPE) in einer Schleife drin ist, verstehe ich ebenfalls nicht. |
AW: Schleifenabbruch durch Esc Taste...
Ganz einfach: das Sleep erlaubt, anderen Prozessen und Threads zu arbeiten. Ohne das Sleep geht die Schleife so schnell durch, wie es dein Prozessor erlaubt - und "blockiert" damit auch den Thread, der sich um die GUI kümmert. Übrigens wird nur ein Kern ausgelastet, nicht mehr - ist ja nur ein Thread und ein Thread kann gleichzeitig nur auf einem Kern laufen.
MfG Dalai |
AW: Schleifenabbruch durch Esc Taste...
Zitat:
PS: Drum bringt es auch wenig sich massig viele Kerne/CPUs zu besorgen, denn wenn es nicht genug Threads gibt, um alle Kerne auszulasten, verschwendet man nur Rechnenleistung. |
AW: Schleifenabbruch durch Esc Taste...
Zitat:
Du reihst Dich ein bei den Urhebern dummer Sprüche: „Ich glaube, dass es auf der Welt einen Bedarf von vielleicht fünf Computern geben wird.“ ![]() |
AW: Schleifenabbruch durch Esc Taste...
16 Kerne für einen Office+Internet-PC sind also besser als 8?
|
AW: Schleifenabbruch durch Esc Taste...
Natürlich, wenn 15 Kerne vor sich hinschlummern statt nur 7, ist das doch viel cooler.
|
AW: Schleifenabbruch durch Esc Taste...
Zitat:
Tschuldijung, Freitag eben... |
AW: Schleifenabbruch durch Esc Taste...
Zitat:
Aber die werden ja großteils blockiert, wenn ich die Schleife ohne Sleep laufen lasse. Es geht dann eben 12 Sekunden lang nichts mehr. Weder in der compilierten Form, noch lässt sich ein anderes externes Fenster anklicken. Der Mauszeiger bleibt solange der Pfeilzeiger. |
AW: Schleifenabbruch durch Esc Taste...
Eigendlich sollte kein Thread in der Lage sein, irgendeinen anderen durch eine Schleife zu "blockieren" (abgesehen von welchen mit niedriger Priorität). Dafür sorgt das Betriebssystem.
Deswegen finde ich auch die Lösung mit dem Sleep irgendwie merkwürdig (und die Erklärung dazu) :gruebel: |
AW: Schleifenabbruch durch Esc Taste...
Jeder Thread bekommt vom System ein "Fenster" von paar Millisekunden, in dem es einen Kern nutzen kann, bevor Windows den Kern für den nächsten Thread freimacht.
Mit einem Sleep(0) kann man sein "Fenster" sofort abbrechen ... damit Windows nicht "sinnlos" den Thread weiter behandelt, obwohl er "jetzt" nichts mehr machen will. Was ist das denn für ein PC? Wieviele Kerne gibt es und wie sind die ausgelastet? (während der Schleife und in den 12 Sekunden, bzw. davor/danach) Wie sieht der RAM aus? (im Cache, Verfügbar, Frei, Ausgelagert und Zugesichert) Bei einer 1-Kern-CPU kann man mit einem Thread ja problemlos alles lahmlegen. -> genausoviel/mehr Aufgaben (ala arbeitende Threads), als Arbeiter (Kerne) |
AW: Schleifenabbruch durch Esc Taste...
Zitat:
Zitat:
Soweit ich weiß, unterbricht Windows die Threads nicht selbst, sondern nur die Prozesse... |
AW: Schleifenabbruch durch Esc Taste...
Wie ich schon schrieb, gibt es das Problem mit der Verzögerung auf den Abbruch bei mir auch nicht ohne Sleep. Ich hab das Sleep nur eingesetzt, um die sinnlose Auslastung der CPU zu unterbinden, weil die Schleife ohne Sleep eben so schnell durchrauscht, wie es die CPU hergibt. Mit Sleep wird die Schleife für einige Millisekunden unterbrochen und dann läuft die Schleife auch merklich langsamer durch. Ein Sleep(0) lastet übrigens genauso aus wie ohne Sleep.
Der Nebeneffekt des Sleep ist, dass auch andere Threads desselben Prozesses Zeit bekommen, auch wenn sie das aufgrund des Schedulers eigentlich sowieso müssten, vor allem bei Mehrkernern. Daher weiß ich nicht genau, warum das Sleep beim Verzögerungsproblem hilft. Ich vermute, dass der GUI-Thread derselbe ist wie der der Schleife - und da der mit der Schleife zu tun hat, kommt er nicht mehr zum Bearbeiten der GUI. MfG Dalai |
AW: Schleifenabbruch durch Esc Taste...
Und wie wäre es mit einem
Delphi-Quellcode:
?
application.processmessages
Gruß K-H |
AW: Schleifenabbruch durch Esc Taste...
Ich meinte nur:
Sleep(0) - Threadwechsel Sleep(1...9999) - Warten und Threadwechsel Dann habe ich deine Intention von 'Sleep(1)' verstanden... |
AW: Schleifenabbruch durch Esc Taste...
Zitat:
MfG Dalai |
AW: Schleifenabbruch durch Esc Taste...
Zitat:
Zitat:
![]() Zitat:
Deswegen: Irgendwas läuft da verkehrt :gruebel: |
AW: Schleifenabbruch durch Esc Taste...
Delphi-Quellcode:
Schon mal überlegt, was alles passiert, wenn die Caption eines Formulars geändert wird?
{...}
Caption := inttostr(i); {...} Da wird nicht nur ein Feld in der VCL-Klasse verändert. |
AW: Schleifenabbruch durch Esc Taste...
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:
Du wirst es vielleicht nicht glauben, aber wenn ich den Task Manager aufrufe und die Leistung anzeige, bleibt selbst die Grafik stehen, die sonst im Sekunden Rhythmus von rechts nach links läuft. Im Ressourcen Monitor werden gleich 8 Kerne angezeigt, obwohl die CPU bloß 4 Kerne hat ?!? Im Ressourcenmonitor bleibt die Grafik nicht hängen und die Kerne 0, 2 und 4 schlagen aus. Ups. Im 2. Versuch bleibr auch der Resourcenmonitor kurz stehen, zeigt dann aber Ausschläge bis fast 100% bei Kernen 2, 4 und 6 an. |
AW: Schleifenabbruch durch Esc Taste...
Zitat:
Das könnte schon ein bisschen Ärger machen. Zitat:
![]() |
AW: Schleifenabbruch durch Esc Taste...
Zitat:
Wenn ich das Caption auskommentiere läuft die Schleife zu schnell ab. Vielleicht eine zweite Schleife rein? Mal sehen. |
AW: Schleifenabbruch durch Esc Taste...
Zitat:
Zitat:
|
AW: Schleifenabbruch durch Esc Taste...
Zitat:
Das passiert alles erst nach dem Ende der Methode, bzw. beim Anzeigen des Abbruch-Dialogs. |
AW: Schleifenabbruch durch Esc Taste...
Zitat:
|
AW: Schleifenabbruch durch Esc Taste...
Zitat:
|
AW: Schleifenabbruch durch Esc Taste...
Zitat:
Wenn ich das Caption rauslasse kann ich ESC drücken und das Form sofort schließen.
Delphi-Quellcode:
Wenn ich jetzt ein 'Caption:=inttostr(i);' einfüge, kann ich auch das Form sofort schliesen.
procedure TForm1.EndlossSchleife;
var i:integer; begin ResetEscPressed; while i <= 100000000 do begin Application.ProcessMessages; if EscPressed('Schleife abbrechen ?') then break; end; Label1.Caption:= 'stop'; end; Erst wenn ich jetzt ein 'inc(i)' reintue, habe ich wieder das Problem |
AW: Schleifenabbruch durch Esc Taste...
Zitat:
Das Caption ist aber schon zum Zähler geworden, nachdem ich den Button angeklickt habe und hat auch beim Drücken der ESC Taste sofort gestoppt. |
AW: Schleifenabbruch durch Esc Taste...
Das procedure TForm1.EndlossSchleife; scheint nicht das Einzige zu sein, was in Deinem Programm abläuft.
Wie wäre es mit dem vollständigen Code...? |
AW: Schleifenabbruch durch Esc Taste...
Zitat:
Zitat:
Also zumindestens nicht im Original. :stupid: Die Frage ist auch, ob man hier wirklich eine Lösung braucht, oder man man nicht besser einen "ordentlichen" und vorallem praxisnaheren Code verwendet. |
AW: Schleifenabbruch durch Esc Taste...
Zitat:
Allerdings hat Himitsu schon recht: richtig bringt es nichts, dem jetzt nachzuspüren ... hast du denn noch Problem mit dem Code in deiner Anwendung? |
AW: Schleifenabbruch durch Esc Taste...
Zitat:
Zitat:
|
AW: Schleifenabbruch durch Esc Taste...
Liste der Anhänge anzeigen (Anzahl: 1)
Seit WIN VISTA gibt es neue APIs, u.a. die wait chain traversal API.
![]() ![]() Man kann im Task Manager mit Rechtsklick auf das verdächtige Programm sehen, ob Threads hängen - siehe Anhang. |
AW: Schleifenabbruch durch Esc Taste...
[QUOTE=BUG;1279134]
Zitat:
es ist wirklich so, dass ich in dieser Anwendung nur diese Schleife laufen ließ, um den Tatenabbruch zu testen, es ist da sonst nichts. Ich wollte jetzt auch nicht unbedingt eine Lawine lostreten. Es genügt mir, dass ich mit 'Sleep' ein Aufhängen des Rechners verhindern kann. Natürlich mache ich mir schon Gedanken, dass eine 'GetAsyncKeyState' einen solchen programmübergreifenden Hänger verursachen kann. Sehe gerade, dass die Funktion der WinApi angehört, also keine, nur Delphi interne Funktion ist. Andererseits habe ich auch schon an Net Framework 1.1 gedacht, das installiert sein muss, um Delphi 2005 überhaupt installieren zu können. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 01:45 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz