Einzelnen Beitrag anzeigen

Dejan Vu
(Gast)

n/a Beiträge
 
#11

AW: Update-Vorgang in einen Thread auslagern

  Alt 19. Dez 2014, 07:32
Die Kommunikation zwischen Threads und der Außenwelt geschieht über synchronisierte Events und geschützte Properties.

Der Thread ackert also im Hintergrund, möchte aber, das sein innerer Zustand (Was macht er gerade? Wie weit ist er?) in einer Form sichtbar ist.

Fein. Dann unterhalten die sich eben, aber nicht direkt, bitte. Das ist praktisch, weil so eine Form auch gut für andere Threads verwendet werden kann und andererseits so ein Thread auch mit einer anderen Form reden kann (oder mit gar keiner, sollte ihm schnurz sein).

Es bieten sich zum Unterhalten Events oder Interfaces an. Beides muss aber synchronisiert werden, d.h. Thread und Außenwelt laufen ja in unterschiedlichen Threads und die VCL ist nicht threadsafe, d.h. alles, was mit der VCL geschieht, muss im Hauptthread gemacht werden.

Nehmen wir mal folgenden Thread;
Delphi-Quellcode:
Procedure TMyThread.Execute;
Begin
  ShowProgressBar();
  MaxSteps := 1000;
  For i:=1 to MaxSteps do begin
     Self.Progress := I;
     UpdateProgressBar();
     DoSomething();
  end;
  HideProgressBar();
End;
Die fraglichen Methoden sind also 'ShowProgressBar', 'UpdateProgressBar' und 'HideProgressBar'.
In jedem Fall müssen die erst einmal per 'Synchronize' (oder 'Queue') aufgerufen werden, denn diese beiden Methoden sorgen dafür, das die Aufrufe im Kontext des VCL-Threads durchgeführt werden.
Also:
Delphi-Quellcode:
Procedure TMyThread.Execute;
Begin
  Synchronize(ShowProgressBar);
  MaxSteps := 1000;
  For i:=1 to MaxSteps do begin
     Self.Progress := I;
     Synchronize(UpdateProgressBar);
     DoSomething();
  end;
  Synchronize(HideProgressBar);
End;
Ok. Nun gibt es (mindestens) zwei Ansätze, wie die konkrete Kommunikation mit einem Formular aussehen kann.
1. Mit Events. Der Thread deklariert drei Eventhandler ,'OnShowProgressBar', 'OnHideProgressBar' und 'OnUpdateProgressBar' (geht auch mit einem Event, aber egal). Das Formular meldet sich auf die Events an und führt die VCL-Änderungen (Progressbar zeigen, verbergen, updaten) aus. So ungefähr
Delphi-Quellcode:
Type
  TMyThread = Class...
  public
     OnShowProgressBar : TNotifyEvent Read FOnShowProgressBar Write FOnShowProgressBar;
     OnHideProgressBar : TNotifyEvent Read FOnHideProgressBar Write FOnHideProgressBar ;
     ...
   end;

Procedure TMyThread.ShowProgressbar;
Begin
  if Assigned (FOnShowProgressBar) Then
     FOnShowProgressBar(Self);
End;
...

Procedure TMyForm.StartThread;
Begin
  FmyThread := TmyThread.Create;
  FmyThread.OnShowProgressBar := ShowProgressBar;
  FmyThread.OnHideProgressBar := HideProgressBar;
...
End;

Procedure TMyForm.ShowProgressBar (Sender : TObject);
Begin
  Progressbar.Visible := True;
End;
Oder mit einem Interface. Dabei erwartet der Thread eine 'View', die die drei Methoden zum Anzeigen der Progressbar bereitstellt.
Delphi-Quellcode:
Type
  IProgessBar = interface
    procedure ShowProgressBar;
    Procedure HideProgressBar;
    Procedure UpdateProgressBar (Position, Total : Integer);
  End;

  TMyThread = class (TThread)
    FProgess : IProgressBar;
  public
    Constructor Create (aProgress : IProgress);
  End;

...
Procedure TMyThread.ShowProgressBar;
Begin
  if Assigned (FProgress) then FProgess.ShowProgressBar;
End;

Procedure TMyThread.UpdateProgressBar;
Begin
  if Assigned (FProgress) then FProgess.UpdateProgressBar (Self.Position, Self.Total);
End;
....

Type
  TMyForm = Class (TForm, IProgress)
  ...
    Procedure ShowProgressBar;
    Procedure HideProgressBar;
    Procedure UpdateProgressBar (Position, Total : Integer);
End;
Das geht alles viel einfacher und besser, aber das Prinzip sollte klar sein. Standardpattern bei Delphi sind die Events. In anderen Programmiersprachen eher die Interfaces (Java kennt z.B. gar keine Delegaten).
  Mit Zitat antworten Zitat