![]() |
AW: Laufende whileschleife auf Knopfdruck unterbrechen
Ich habe noch ganz vergessen zu erwähnen, dass es noch ein Konzept gibt, dass weder Threads noch
Delphi-Quellcode:
benötigt.
Application.ProcessMessages
Jede Anwendung geht immer wieder in den Idle-State. Das bekommt man mit, wenn man
Delphi-Quellcode:
oder in der VCL
Application.OnIdle
Delphi-Quellcode:
bestückt.
TApplicationEvents.OnIdle
Anstatt also jetzt die Schleife in einem Rutsch auszuführen, legt man den nächsten Arbeitsschritt fest und wartet, bis man durch
Delphi-Quellcode:
wieder aufgerufen wird. Jetzt erfolgt die Abarbeitung der Schritte im Main-Thread, nach jedem Schritt werden alle Nachrichten der Anwendung abgearbeitet und im Anschluss daran kommt der Idle-Event, der dann den nächsten Schritt anstösst.
OnIdle
Das geht zwar langsamer als in einem Thread, blockiert die Anwendung aber nicht so heftig wie die Schleife in ein Rutsch auszuführen. ;) |
AW: Laufende whileschleife auf Knopfdruck unterbrechen
Moin zusammen,
vielen Dank für die Antworten. Ich habe es in dieser Form versucht. Das Problem klärt sich dadurch aber noch nicht:
Delphi-Quellcode:
Ich kann allerdings auch weiterhin den Disconnectknopf nur dann mit Reaktion drücken wenn die Schleife nicht läuft. Unter untenstehendem Link ist einmal das gezipte Projekt. Entscheidender Part ist CForm_WLNNMEA.
procedure TForm_WLNConnectionNMEA.IdTCPClient1Connected(Sender: TObject);
begin a:=true; PackageProcess.clear(Memo); Memo.Lines.Add('connected'); Button_Disconnect.Enabled := true; while a=true do begin Application.ProcessMessages; PackageProcess.ReceiveString(IdTCPClient1); PackageProcess.selectNMEA (); PackageProcess.showmessage(Memo); a:=PackageProcess.GetConnectState; end end; procedure TForm_WLNConnectionNMEA.Button_DisconnectClick(Sender: TObject); begin PackageProcess.SetConnectStateFalse; PackageProcess.DisconnectFromHost(Memo,IdTCPClient1); end; ![]() Vielleicht sieht ja jemand meinen Fehler. Als nächstes test ich sonst den OnIdle Vorschlag. |
AW: Laufende whileschleife auf Knopfdruck unterbrechen
Da ich per PN danach gefragt wurde, hier eine (schnell dahin getippte) Variante für so einen
Delphi-Quellcode:
:
IdleJob
Die Basis:
Delphi-Quellcode:
Eine Loop Ableitung:
unit uIdleJob;
interface uses {System.}Classes, {TNotifyEvent} {Vcl.}AppEvnts; {TApplicationEvents} type TJobFinishState = ( jfsCancelled, jfsFinished ); TFinishNotifyEvent = procedure( Sender: TObject; State: TJobFinishState ) of object; TIdleJob = class abstract private FAppEvnt: TApplicationEvents; FOnFinish: TFinishNotifyEvent; FOnStep: TNotifyEvent; procedure HandleOnIdle( Sender: TObject; var Done: Boolean ); function GetIsRunning: Boolean; procedure DoOnFinish( AState: TJobFinishState ); procedure DoOnStep; protected procedure DoStart; virtual; procedure DoStep; virtual; abstract; procedure DoStop; virtual; procedure JobFinished( NotifyLastStep: Boolean = True ); public procedure AfterConstruction; override; procedure BeforeDestruction; override; procedure Start; procedure Stop; property IsRunning: Boolean read GetIsRunning; property OnFinish: TFinishNotifyEvent read FOnFinish write FOnFinish; property OnStep: TNotifyEvent read FOnStep write FOnStep; end; implementation { TIdleJob } procedure TIdleJob.AfterConstruction; begin inherited; FAppEvnt := TApplicationEvents.Create( nil ); end; procedure TIdleJob.BeforeDestruction; begin FAppEvnt.Free; inherited; end; procedure TIdleJob.DoOnFinish( AState: TJobFinishState ); begin if Assigned( FOnFinish ) then FOnFinish( Self, AState ); end; procedure TIdleJob.DoOnStep; begin if Assigned( FOnStep ) then FOnStep( Self ); end; procedure TIdleJob.JobFinished( NotifyLastStep: Boolean ); begin FAppEvnt.OnIdle := nil; if NotifyLastStep then DoOnStep; DoOnFinish( jfsFinished ); end; procedure TIdleJob.DoStart; begin end; procedure TIdleJob.DoStop; begin end; function TIdleJob.GetIsRunning: Boolean; begin Result := Assigned( FAppEvnt.OnIdle ); end; procedure TIdleJob.HandleOnIdle( Sender: TObject; var Done: Boolean ); begin DoStep( ); if IsRunning then DoOnStep; end; procedure TIdleJob.Start; begin if IsRunning then Exit; FAppEvnt.OnIdle := HandleOnIdle; DoStart; DoOnStep; end; procedure TIdleJob.Stop; begin if not IsRunning then Exit; FAppEvnt.OnIdle := nil; DoStop; DoOnFinish( jfsCancelled ); end; end.
Delphi-Quellcode:
und jetzt mit einer Form zusammen
unit uMyLoopJob;
interface uses System.SysUtils, uIdleJob; type TMyLoopJob = class( TIdleJob ) private FFrom, FTo, FStep: Integer; FCurrent: Integer; protected procedure DoStart; override; procedure DoStep; override; procedure DoStop; override; public constructor Create( const AFrom, ATo, AStep: Integer ); property Current: Integer read FCurrent; end; implementation { TMyLoopJob } constructor TMyLoopJob.Create( const AFrom, ATo, AStep: Integer ); begin inherited Create; FFrom := AFrom; FTo := ATo; FStep := AStep; end; procedure TMyLoopJob.DoStart; begin inherited; FCurrent := FFrom; end; procedure TMyLoopJob.DoStep; begin inherited; Sleep( 20 ); // Wir simulieren mal ein bisserl Rechenlast Inc( FCurrent ); if FCurrent >= FTo then begin FCurrent := FTo; JobFinished( True ); end; end; procedure TMyLoopJob.DoStop; begin inherited; // nichts zu tun hier end; end.
Delphi-Quellcode:
Was man hier schön sieht:
unit Unit2;
interface uses uIdleJob, uMyLoopJob, Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ComCtrls; type TForm2 = class( TForm ) StartLoopButton: TButton; StopLoopButton: TButton; ProgressBar1: TProgressBar; Label1: TLabel; procedure StartLoopButtonClick( Sender: TObject ); procedure StopLoopButtonClick( Sender: TObject ); private FLoopJob: TMyLoopJob; procedure LoopJobStep( Sender: TObject ); public procedure AfterConstruction; override; procedure BeforeDestruction; override; end; var Form2: TForm2; implementation {$R *.dfm} { TForm2 } procedure TForm2.AfterConstruction; begin inherited; FLoopJob := TMyLoopJob.Create( 1, 100, 1 ); FLoopJob.OnStep := LoopJobStep; end; procedure TForm2.BeforeDestruction; begin FLoopJob.Free; inherited; end; procedure TForm2.StartLoopButtonClick( Sender: TObject ); begin FLoopJob.Start; end; procedure TForm2.StopLoopButtonClick( Sender: TObject ); begin FLoopJob.Stop; end; procedure TForm2.LoopJobStep( Sender: TObject ); begin Label1.Caption := IntToStr( FLoopJob.Current ); ProgressBar1.Position := FLoopJob.Current; end; end. Die Basis kümmert sich um den gesamten Verwaltungskram, der konkrete Job nur noch um sich selber und die Form steuert/reagiert nur noch. Oder anders ausgedrückt, je konkreter ich werde umso weniger Code muss ich schreiben ;) |
AW: Laufende whileschleife auf Knopfdruck unterbrechen
Kann es sein, dass der API Aufruf blockierend ist? Also erst zurückkehrt, wenn er ausgeführt wurde?
|
AW: Laufende whileschleife auf Knopfdruck unterbrechen
Imho haben die Indies nur in Threads etwas zu suchen. Weiterhin ist das 'Connected' Event nicht der richtige Ort, um eine Schleife zu implementieren.
Soweit ich mich erinnere, hebeln die Indies das Eventkonzept der TCP-Behandlung von Windows komplett aus. Diese ist -zugegebenermaßen- nicht so einfach umzusetzen, weil man doch anders denken muss. Die Indies versuchen also, dem normalen Programmierer entgegenzukommen. Dazu gehört die synchrone Arbeit. Ich lese....ich verarbeite...ich schreibe.... Wärend ich lese oder schreibe, hängt das System. Es gibt zwar eine Komponente, (AntiFreeze), die das hängen verhindern soll, aber das ist ja auch nicht das richtige. Ich würde also die ganze Abarbeitung in einen Thread verlagern und mit (synchronisierten) Events arbeiten. Während im Hintergrund I/O (blockierend oder nicht: wurscht) läuft, kann ich im Vordergrund weiter mit meiner UI arbeiten. Ein Abbruch-Button würde den Thread dann signalisieren, das -sofern er das zulässt- Feierabend gemacht werden darf. |
AW: Laufende whileschleife auf Knopfdruck unterbrechen
Vielen Dank nochmal für eure Hilfe. Ich habe das Problem nun mit Threads gelöst und es
läuft wunderbar. :thumb: Tolle Hilfe |
Alle Zeitangaben in WEZ +1. Es ist jetzt 22:18 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 by Thomas Breitkreuz