Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi Pagecontrol und Threads? (https://www.delphipraxis.net/166515-pagecontrol-und-threads.html)

Chriscode 16. Feb 2012 09:58

Pagecontrol und Threads?
 
Hallo zusammen,
ich programmiere gerade eine Updatefunktion die eine Art Downloadmanager beinhaltet. Für die Downloads benutze ich die Klasse TThread. Meine Updatefunktion übergibt die Downloadlinks zu mehrere zu erneuernde Dateien und erzeugt für jede Datei ein TabSheetEx, den Downloadthread und eine progressbar auf der PageControl. Da die Dateien teilweise recht groß sind sollten diese parallel heruntergeladen werden können.

Im Prinzip geht es mir nur darum, den Fortschritt der einzelnen Dateien optisch mit Progressbars darzustellen.

Jetzt habe ich mir das IndyHTTPGetThreaded Demo von Luckie heruntergeladen (an dieser Stelle vielen Dank dafür) und stehe nun vor dem Problem die Threads mit der Pagecontrol / dem Tabsheet zu "verbinden". Oder besser gesagt: Wie kann ich dem Thread mitteilen welche Page zu ihm gehört?

Meine Progressbar kann ich ja z.B. so mit dem Tabsheet verbinden:
Code:
probar := TProgressbar.Create(TabSheetEx);
TOleControl(TabSheetEx.probar).Parent := TabSheetEx;
Die Downloadthreads müssen ja wissen auf welchem Tabsheet sie aktiv sind und auf diesem dann die Progressbar verändern, den Tab schließen etc. Das Problem ist nicht grundlegende Funktionsweise von beiden Punkten sondern wie ich sie kombinieren kann.

Ich hoffe meine Fragestellung ist konkret genug um sie beantworten zu können. Mein Problem ist, mir fehlt eben schon ein vernünftiger Ansatz. Oder ist die Idee über das Tabsheet hier generell zu umständlich?

Vielen Dank.

Gruß
Chris

DeddyH 16. Feb 2012 10:12

AW: Pagecontrol und Threads?
 
Spendier Deiner Threadklasse doch einfach ein Event, das sie alle X heruntergeladenen Bytes feuern kann.
Delphi-Quellcode:
type
  TDownloadEvent = procedure(Sender: TObject; CurrentSize, TotalSize: int64) of object;

  TDeinThread = class(TThread)
  private
    FDownloadEvent: TDownloadEvent;
    procedure DoOnProgress;
    ...
  public
    ...
    property DownloadEvent: TDownloadEvent read FDownloadEvent write FDownloadEvent;

procedure TDeinThread.Execute;
begin
  //arbeiten
  if (HeruntergeladeneBytes mod 500 = 0) then
    Synchronize(DoOnProgress);
  ...
end;

procedure TDeinThread.DoOnProgress;
begin
  if Assigned(FDownloadEvent) then
    FDownloadEvent(self, HeruntergeladeneBytes, BytesGesamt);
end;
Den Thread muss Du nun noch Suspended anlegen, damit Du noch die Properties zuweisen kannst, und dann sollte das im Groben funktionieren.

Chriscode 16. Feb 2012 10:23

AW: Pagecontrol und Threads?
 
Hallo Detlef,
vielen Dank für deine Antwort.

Ich glaube du bist mir allerdings gedanklich schon mehr als ein paar Schritte voraus :shock:

Bei deinem Beispiel wüsste ich nicht wo jetzt konkret auf die Progressbar des Tabsheets zugegriffen wird. Und woher der Downloadthread weiß auf welchem Tab er beheimatet ist?

Mir fehlt anscheinend einfach das Wissen wie sich beides kombinieren lässt.

Meinen Downloadthread starte ich so:
Code:
 DownloadThread := TDownloadThread.Create(True);
   DownloadThread.FreeOnTerminate := True;
   DownloadThread.URL := updatesrc;
   DownloadThread.start;
Demnach weiß der Downloadthread überhaupt nicht zu welchem Tab er gehört :oops:

Gruß
Chris

DeddyH 16. Feb 2012 10:32

AW: Pagecontrol und Threads?
 
Der Thread selbst gehört ja zu gar keinem Tab. In meinem Beispiel würdest Du nun 3 Methoden anlegen (geht auch mit einer, aber wir machen es erst einmal einfach) und diese dem Event des jeweiligen Threads zuweisen.
Delphi-Quellcode:
DownloadThread := TDownloadThread.Create(true);
DownloadThread.DownloadEvent := ProgressMethod;
Wobei ProgressMethod dann eine Methode vom Typ TDownloadEvent ist, also die Parameter Sender, CurrentSize und TotalSize besitzt.
Delphi-Quellcode:
procedure TTabForm.ProgressMethod(Sender: TObject; CurrentSize, TotalSize: int64);
begin
  (* Aus Jux selbst berechnet *)
  ProgressBarThread1.Position := Round(CurrentSize / TotalSize * 100);
end;

Chriscode 16. Feb 2012 11:10

AW: Pagecontrol und Threads?
 
Hallo nochmal,
erneut meinen herzlichen Dank an dich für deinen hilfreichen Beitrag.

Was ich jetzt wieder einmal nicht weiß, wie kann ich die richtige Progreessbar ansprechen? Du schreibst "ProgressBarThread1". Die Progressbar lasse ich ja dynamisch erzeugen. Das ist ja genau der Punkt den ich Anfangs meinte. Ich hatte überlegt namen zu übergeben und findcomponent zu nutzen, aber das kann wohl nicht im Sinne des Erfinders sein.

Im übrigen erhalte ich die Fehlermeldung "ungültige GLeitkommaoperation" an der Stelle deiner Jux-Berechnung :lol: Aber das könnte natürlich auch daran liegen das ich die falsche progressbar anspreche. Ich habe nämlich einfach "probar.position" genommen.

Gruß
Chris

DeddyH 16. Feb 2012 12:06

AW: Pagecontrol und Threads?
 
Du brauchst keinen Namen für die Progressbar, sondern kannst ja auch die Instanz selbst ansprechen. Die musst Du Dir halt irgendwo merken, am Besten verknüpfst Du sie dann gleich mit der Thread-Instanz (wie, das überlasse ich Dir). Der Fehler dürfte übrigens daher rühren, dass TotalSize nahe gegen 0 geht oder gar 0 ist, das gibt dann natürlich Probleme bei der Division. Aber darum ging es ja auch gar nicht ;)

Chriscode 16. Feb 2012 13:14

AW: Pagecontrol und Threads?
 
okay... ich komme mir langsam wirklich hilflos vor. Du hast mir jetzt schon ordentlich weitergeholfen aber der Funke will nicht gänzlich überspringen.

Könntest du mir nicht vielleicht ein kleines -meinetwegen auch allgemeines- Beispiel geben wie ich dies anstellen kann?

Mir gehts jetzt weniger konkret um die Progressbar das muss ich selbst hinbekommen. Vielmehr darum wie der Thread eben die Komponenten von der Page ansteuern kann. Das was nunmal auch meine Ausgangsfrage war.

Mit der Prozedur habe ich jetzt schonmal ein gutes Werkzeug zur Hand aber ich weiß nicht wie es genau anwenden kann.

Also nochmal ganz konkret gefragt:
1) Wie kann ich den Sheet an sich ansprechen der zur Prozedur gehört und diesen z.B. schließen?
(Komponente.pages[?] as TTabSheetEx).free ?

2) Wie kann ich Komponenten auf dem Sheet ansteuern z.B die Progressbar?

Gruß
Chris

DeddyH 16. Feb 2012 13:32

AW: Pagecontrol und Threads?
 
Da gibt es mehrere Möglichkeiten. Die Einfachste wäre, dem Thread eine Property vom Typ TProgressBar zu verpassen. Dann könnte man sich auch das Event sparen, da dann der Thread direkt auf seine Property zurückgreifen und sie synchronisiert aktualisieren könnte. Der Nachteil ist die starke Bindung, denn wenn man später einmal die ProgressBar gegen z.B. eine TGauge austauschen möchte, muss man an mehreren Stellen ändern. Um also flexibel zu bleiben, lassen wir unseren Event so wie er ist. Nun müssen wir noch irgendwie Thread und das zu aktualisierende Control miteinander verknüpfen. Das ginge beispielsweise mit einem Record und einer Liste.
Delphi-Quellcode:
type
  PVerknuepfung = ^TVerknuepfung;
  TVerknuepfung = record
    Thread: TDownloadThread;
    ProgressBar: TProgressBar;
  end;
Wenn wir nun noch eine TList anlegen, können wir dort Elemente vom Typ PVerknuepfung reinpacken.
Delphi-Quellcode:
var
  Verknuepfung: PVerknuepfung;
  PB: TProgressBar;
  DT: TDownloadThread;
begin
  PB := TProgressBar.Create(nil);
  PB.Parent := ...
  //usw.
  DT := TDownloadThread.Create;
  //usw.
  New(Verknuepfung);
  Verknuepfung^.Thread := DT;
  Verknuepfung^.ProgressBar := PB;
  Liste.Add(Verknuepfung);
end;
Wenn nun einer der Threads das Event feuert, könnte man die Liste durchlaufen und schauen, in welchem Element er drinsteht (er übergibt sich ja selbst im Sender-Parameter).
Delphi-Quellcode:
Index := 0;
PB := nil;
while (Index < Liste.Count) and not Assigned(PB) do
  begin
    if TVerknuepfung(Liste[Index]^).Thread = Sender then
      PB := TVerknuepfung(Liste[Index]^).ProgressBar;
    inc(Index);
  end;
So, nun haben wir die zugehörige ProgressBar ermittelt (oder auch nicht, dann ist sie nil) und können sie aktualisieren.
Delphi-Quellcode:
if Assigned(PB) then
  PB.Position := ErrechneterWert;
Das mag jetzt nicht die allereleganteste Methode sein, sie sollte aber eigentlich funktionieren (ohne Gewähr, da aus dem Kopf getippt) und halbwegs verständlich sein.

Chriscode 17. Feb 2012 10:48

AW: Pagecontrol und Threads?
 
Hallo Detlef,
vielen Dank, du hast mir mit deinen Beiträgen sehr geholfen :thumb:

Gruß
Chris

DeddyH 17. Feb 2012 10:54

AW: Pagecontrol und Threads?
 
Das freut mich :)


Alle Zeitangaben in WEZ +1. Es ist jetzt 19:06 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