Autor Beitrag
jayjay2
Hält's aus hier
Beiträge: 4



BeitragVerfasst: Di 18.09.07 15:40 
Hallo!

Wie im Titel angekündigt benutze ich Threads um einige Dateien runterzuladen. Allerdings sieht mir das ganze nicht besonders schön aus. Vielleicht weiss einer wie es effektiver geht ohne es zu kompliziert zu machen? (Um es nochmal zu verdeutlichen: Der Code läuft fehlerfrei!)

Was will ich programmieren?
Die Dateiliste befindet sich in einem dynamischen array 'AllData'. Nun will alle Dateien aus der Liste runterladen indem ich 10 Threads benutze. Der gesamte Download wird in einer Funktion 'Update1' ausgeführt. Der Fortschritt wird in Form_Progress.Listbox_Log sichtbar gemacht.

ausblenden volle Höhe Code-'Skizze'
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
unit unit1;

...

type
  TDownload = class(TThread)
  public
    Index: integer;  // Datei-Index im array
    Nbr: integer;    // Zahl die die runtergeladene datei beschreibt - unwichtig
    Form_Progress: TForm_Progress; 
  protected
    procedure Execute; override;
end;

...

function Update1(Index: integer): integer;  // Funktion die den Download durchführt

implementation

...

procedure TDownload.Execute;
begin
  try
    Nbr := Update1(AllData[Index]);
    Form_Progress.ListBox_Log.Items.Add(AllData[Index]+' - '+IntToStr(Nbr));
    Form_Progress.ListBox_Log.TopIndex := Form_Progress.ListBox_Log.Count-1;
  except
    Form_Progress.ListBox_Log.Items.Add(AllData[Index]+' - Error occured');
    Form_Progress.ListBox_Log.TopIndex := Form_Progress.ListBox_Log.Count-1;
  end;
  Terminate;  // ! ? ! ? ! ? ! ? ! ? ! ? ! ? ! ? ! ? 
              // Ich will den Thread nicht automatisch schliessen lassen, sonst weiss ich           
              // nicht wie ich erkennen soll ob er schon fertig ist. Deswegen kommt etwas
              // später auch die Zeile 'DownloadThreads[j].FreeOnTerminate := False;'
end;


procedure TForm_Main.Button_UpdateClick(Sender: TObject);  // Hauptfunktion
var
  i, j: integer;
  Nbr: integer;
  Form_Progress: TForm_Progress;
  DownloadThreads: array [0..9of TDownload;
begin

  Form_Progress := TForm_Progress.Create(Self);
  Form_Progress.Show;
  Form_Progress.Borderstyle := bsSingle;
  StopDownloading := False;  // globale variable die im Fenster Form_Progress mittels 
                             // 'Cancel'-Button geändert wird

  // die ersten 10 threads starten
  for j := 0 to 9 do
  begin
    DownloadThreads[j] := TDownload.Create(True);
    DownloadThreads[j].FreeOnTerminate := False;
    DownloadThreads[j].Index := j;  // erste 10 Dateien reinschreiben
    DownloadThreads[j].Form_Progress := Form_Progress;
    DownloadThreads[j].Resume;
  end;

  // falls ein thread fertig sein sollte, wird er freigegeben und neu erstellt
  i := 10// die ersten 10 dateien werden schon runtergeladen
  repeat
    for j := 0 to 9 do  // Threads solange durchlaufen bis einer fertig ist
    begin
      if DownloadThreads[j].Terminated then
      begin
        DownloadThreads[j].Free;    // Alten Thread freigeben...
        DownloadThreads[j] := TDownload.Create(True);  // ...und neu schreiben
        DownloadThreads[j].FreeOnTerminate := False;
        DownloadThreads[j].Index := i;  // Nächste Datei
        DownloadThreads[j].Form_Progress := Form_Progress;
        DownloadThreads[j].Resume;
        Inc(i);
        Form_Progress.Label_Nbr.Caption := IntToSTr(i-9)+'/'+IntToStr(Length(AllData));
        Form_Progress.Refresh;
        Application.ProcessMessages;
        break; // damit dieselbe datei nicht an 2 threads übergeben wird
      end;
    end;
    if StopDownloading = True then break;
    Delay(200); // Delay Funktion von Luckie.
  until i >= Length(AllData); // bis alle Dateien geladen wurden

  // Warten bis alle Threads fertig sind und dann freigeben
  j := 0;
  repeat
    if DownloadThreads[j].Terminated then
    begin
      DownloadThreads[j].Free;
      Inc(j);
      // Informationen noch in die ProgressForm schreiben
      Inc(i);
      Form_Progress.Label_Nbr.Caption := IntToSTr(i-9)+'/'+IntToStr(Length(AllData));
      Form_Progress.Refresh;
    end;
    Delay(50);
  until j > 9// bis alle Threads fertig sind

end;

...
alzaimar
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2889
Erhaltene Danke: 13

W2000, XP
D6E, BDS2006A, DevExpress
BeitragVerfasst: Di 18.09.07 16:47 
Dein Thread ist abhängig von der 'Form_Progress'. Das ist unnötig. Implementiere lieber ein Event 'OnProgress', das Du im Thread per Synchronize aufrufst. Deine Form kann dann einen eigenen Progress-Handler implementieren und dem Event zuweisen.

Auf diese Weise erhältst Du einen wiederverwendbaren und allgemeingültigen Download-Thread.

_________________
Na denn, dann. Bis dann, denn.
jayjay2 Threadstarter
Hält's aus hier
Beiträge: 4



BeitragVerfasst: Di 18.09.07 19:09 
user profile iconalzaimar hat folgendes geschrieben:
Dein Thread ist abhängig von der 'Form_Progress'. Das ist unnötig. Implementiere lieber ein Event 'OnProgress', das Du im Thread per Synchronize aufrufst. Deine Form kann dann einen eigenen Progress-Handler implementieren und dem Event zuweisen.

Auf diese Weise erhältst Du einen wiederverwendbaren und allgemeingültigen Download-Thread.


Danke für die Antwort. Wenn ich mal Zeit habe, werde ich es probieren. Dieser Code war das erste Mal, dass ich mit Threads gearbeitet habe und mein Wissen hab ich mir grösstenteils nur aus dem Forum hier angeeignet (inkl. Links natürlich :)).