AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Laufende whileschleife auf Knopfdruck unterbrechen

Ein Thema von HL92 · begonnen am 13. Feb 2015 · letzter Beitrag vom 24. Feb 2015
Antwort Antwort
Seite 2 von 2     12   
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#11

AW: Laufende whileschleife auf Knopfdruck unterbrechen

  Alt 14. Feb 2015, 16:29
Ich habe noch ganz vergessen zu erwähnen, dass es noch ein Konzept gibt, dass weder Threads noch Application.ProcessMessages benötigt.

Jede Anwendung geht immer wieder in den Idle-State. Das bekommt man mit, wenn man Application.OnIdle oder in der VCL TApplicationEvents.OnIdle bestückt.

Anstatt also jetzt die Schleife in einem Rutsch auszuführen, legt man den nächsten Arbeitsschritt fest und wartet, bis man durch OnIdle 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.

Das geht zwar langsamer als in einem Thread, blockiert die Anwendung aber nicht so heftig wie die Schleife in ein Rutsch auszuführen.
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)
  Mit Zitat antworten Zitat
HL92

Registriert seit: 7. Jan 2015
8 Beiträge
 
#12

AW: Laufende whileschleife auf Knopfdruck unterbrechen

  Alt 16. Feb 2015, 10:28
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:
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;
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.

https://www.dropbox.com/s/b09b0wvn82...EA1.3.zip?dl=0

Vielleicht sieht ja jemand meinen Fehler. Als nächstes test ich sonst den OnIdle Vorschlag.

Geändert von HL92 (16. Feb 2015 um 10:40 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#13

AW: Laufende whileschleife auf Knopfdruck unterbrechen

  Alt 16. Feb 2015, 19:31
Da ich per PN danach gefragt wurde, hier eine (schnell dahin getippte) Variante für so einen IdleJob :

Die Basis:
Delphi-Quellcode:
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.
Eine Loop Ableitung:
Delphi-Quellcode:
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.
und jetzt mit einer Form zusammen
Delphi-Quellcode:
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.
Was man hier schön sieht:

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
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)
  Mit Zitat antworten Zitat
Benutzerbild von Luckie
Luckie

Registriert seit: 29. Mai 2002
37.621 Beiträge
 
Delphi 2006 Professional
 
#14

AW: Laufende whileschleife auf Knopfdruck unterbrechen

  Alt 16. Feb 2015, 22:03
Kann es sein, dass der API Aufruf blockierend ist? Also erst zurückkehrt, wenn er ausgeführt wurde?
Michael
Ein Teil meines Codes würde euch verunsichern.
  Mit Zitat antworten Zitat
Dejan Vu
(Gast)

n/a Beiträge
 
#15

AW: Laufende whileschleife auf Knopfdruck unterbrechen

  Alt 17. Feb 2015, 08:18
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.

Geändert von Dejan Vu (17. Feb 2015 um 08:24 Uhr)
  Mit Zitat antworten Zitat
HL92

Registriert seit: 7. Jan 2015
8 Beiträge
 
#16

AW: Laufende whileschleife auf Knopfdruck unterbrechen

  Alt 24. Feb 2015, 13:31
Vielen Dank nochmal für eure Hilfe. Ich habe das Problem nun mit Threads gelöst und es
läuft wunderbar. Tolle Hilfe
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 2 von 2     12   


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 12:57 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz