Entwickler-Ecke
Grafische Benutzeroberflächen (VCL & FireMonkey) - Progressbar in eigenem Thread
LittleBen - Do 08.09.11 11:07
Titel: Progressbar in eigenem Thread
Hallo,
wollte euch fragen, ob das so OK ist, wie die Progressbar laufen lasse:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| type TMyThread = class(TThread) private FProgressBar: TProgressBar; procedure SetProgressBar(const Value: TProgressBar) ; protected procedure execute; override; public constructor Create; property ProgressBar: TProgressBar read FProgressBar write SetProgressBar; end; |
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19:
| procedure TMyThread.Execute; var n: integer; begin try FProgressbar.Position:= 0; FProgressbar.Max:= 100;
for n:= 0 to 100 do FProgressbar.Position:= FProgressbar.Position+1; except on e: exception do; end; end;
constructor TMyThread.Create; begin inherited Create(true); FreeOnTerminate:= true; end; |
Delphi-Quelltext
1: 2: 3: 4:
| procedure TMyThread.SetProgressBar(const Value: TProgressBar) ; begin FProgressBar:= Value; end; |
Kann ich das so machen, ohne die Regeln des Threaden zu brechen?
Viele Grüße,
Benny
Moderiert von
Narses: Topic aus Sonstiges (Delphi) verschoben am Do 08.09.2011 um 21:27
Gausi - Do 08.09.11 11:41
Ein ganz klares "Nein": Eine Progressbar ist eine visuelle Komponente, und es gilt:
Quelltext
1:
| Visuelle Komponenten + zweiter Thread = Furchtbar Böse™. |
Zugriff auf die VCL von einem zweiten Thread aus ist nur per Synchronize oder vergleichbaren Techniken erlaubt.
LittleBen - Do 08.09.11 11:44
Ah, also habe ichs doch falsch gemacht. Also brauche ich eine Procedure die in der Schleife Synchronisiert wird?
jaenicke - Do 08.09.11 12:07
Nein, übergib dem Thread einfach das Handle der ProgressBar und setze mit PBM_SETPOS direkt die Position. ;-)
http://msdn.microsoft.com/en-us/library/bb760844.aspx
// EDIT:
Das sieht so aus als würdest du hier den Thread pausiert starten, mit Resume fortsetzen und per FreeOnTerminate freigeben? Ganz böse. ;-)
(Ja, ich weiß, bei deinen Delphiversionen war Resume noch nicht entsprechend markiert. ;-))
Übergib das Handle lieber in einem eigenen Konstruktor und lasse den Thread sofort loslaufen.
LittleBen - Do 08.09.11 12:14
Wie ist das denn passiert? Entschuldigung für den Doppelpost. War keine absicht!
LittleBen - Do 08.09.11 12:32
jaenicke hat folgendes geschrieben : |
Das sieht so aus als würdest du hier den Thread pausiert starten, mit Resume fortsetzen und per FreeOnTerminate freigeben? Ganz böse. |
Echt, ist das böse? Habe es so in irgendwelchen Tutorials gesehen. Wie mache ich es dann?
jaenicke hat folgendes geschrieben : |
Nein, übergib dem Thread einfach das Handle der ProgressBar und setze mit PBM_SETPOS direkt die Position. |
Mhh, ist das nicht ein bisschen unsauber?
EDIT: Darf ich das so machen?
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21:
| procedure TMyThread.Execute; var n: integer; begin try for n:= 0 to 100 do Synchronize(Refresh); except on e: exception do; end; end;
procedure TMyThread.Refresh; begin FProgressbar.Position:= FProgressbar.Position + 1; end;
constructor TMyThread.Create; begin inherited Create(true); FreeOnTerminate:= true; end; |
Andreas L. - Do 08.09.11 13:04
Sinnvoller wäre es über ein Ereignis:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22:
| TMyOnProgressEvent = procedure(APos, AMax: Integer) of object; TMyThread = class(TThread) private FOnProgress: TMyOnProgressEvent; published property OnProgress: TMyOnProgressEvent read FOnProgress write FOnProgress; end;
...
procedure TMyThread.Execute; begin
for i := 0 to 100 do begin if Assigned(FOnprogress) then Synchronize(OnProgress(i, 100)); end;
end; |
LittleBen - Do 08.09.11 13:13
Dann bekomme ich die Fehlermeldung: [Fehler] U_Main.pas(120): Es gibt keine überladene Version von 'Synchronize', die man mit diesen Argumenten aufrufen kann
EDIT:
So darf ich das doch machen, oder?
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| type TMyThread = class(TThread) private FProgressBar: TProgressBar; procedure DoProgress; procedure SetProgressBar(const Value: TProgressBar) ; protected procedure execute; override; public constructor Create; property ProgressBar: TProgressBar read FProgressBar write SetProgressBar; end; |
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| procedure TMyThread.Execute; var n: integer; begin try for n:= 0 to 100 do Synchronize(DoProgress) ; except on e: exception do; end;
end; |
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9:
| procedure TMyThread.SetProgressBar(const Value: TProgressBar) ; begin FProgressBar:= Value; end;
procedure TMyThread.DoProgress; begin FProgressBar.Position:= FProgressBar.Position+1; end; |
jaenicke - Do 08.09.11 13:39
Synchronisieren ist hier wenig sinnvoll...
Schließlich soll die Operation durch den Thread doch gerade vom Hauptthread abgekoppelt werden. Und dann für die Fortschrittsanzeige zu synchronisieren... :shock:
LittleBen hat folgendes geschrieben : |
jaenicke hat folgendes geschrieben : | Das sieht so aus als würdest du hier den Thread pausiert starten, mit Resume fortsetzen und per FreeOnTerminate freigeben? Ganz böse. | Echt, ist das böse? Habe es so in irgendwelchen Tutorials gesehen. Wie mache ich es dann? |
Das Problem ist, dass der Thread schon fertig sein kann, bevor Resume selbst durch ist. Und dann knallt es.
Deshalb ist Resume mittlerweile auch als veraltet markiert. Es sollte schlicht nie verwendet werden. Wozu auch? Die Startparameter kannst du als Parameter mitgeben und warten kannst du mit TEvent oder ähnlichem, wenn der Start verzögert werden soll.
LittleBen hat folgendes geschrieben : |
jaenicke hat folgendes geschrieben : | Nein, übergib dem Thread einfach das Handle der ProgressBar und setze mit PBM_SETPOS direkt die Position. | Mhh, ist das nicht ein bisschen unsauber? |
Nein, warum? Das ist genau der beste Weg hier.
LittleBen - Do 08.09.11 13:58
jaenicke hat folgendes geschrieben : |
Synchronisieren ist hier wenig sinnvoll...
Schließlich soll die Operation durch den Thread doch gerade vom Hauptthread abgekoppelt werden. Und dann für die Fortschrittsanzeige zu synchronisieren... :shock:
|
Stimmt, das macht kein Sinn. Hab ich von hier abgeschaut:
http://delphi.about.com/od/kbthread/a/thread-gui.htm
jaenicke hat folgendes geschrieben : |
Nein, übergib dem Thread einfach das Handle der ProgressBar und setze mit PBM_SETPOS direkt die Position. |
Kannst du mir das bitte erklären. Verstehe das mit dem PBM_SETPOS nicht.
jaenicke - Do 08.09.11 14:08
Ich weiß nicht genau wo jetzt das Problem liegt?
Delphi-Quelltext
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:
| uses CommCtrl;
TMyLittleThread = class(TThread) private FProgressBarHandle: THandle; protected procedure Execute; override; public constructor Create(AProgressBarHandle: THandle); end;
constructor TMyLittleThread.Create(AProgressBarHandle: THandle); begin FProgressBarHandle := AProgressBarHandle; FreeOnTerminate := True; inherited Create(False); end;
procedure TMyLittleThread.Execute; var i: Integer; begin for i := 1 to 100 do begin SendMessage(FProgressBarHandle, PBM_SETPOS, i, 0); Sleep(100); end; end;
procedure TForm1.Button1Click(Sender: TObject); begin TMyLittleThread.Create(ProgressBar1.Handle); end; |
LittleBen - Do 08.09.11 14:19
Ahhhh, so meinst du das! Vielen Dank!
Wenn ich auch noch ein Memo beschreiben will, dann kann ich dass ja auch mit Sendmessage machen, oder?
jaenicke - Do 08.09.11 14:26
Klar:
Delphi-Quelltext
1: 2:
| SendMessage(FMemoHandle, WM_SETTEXT, 0, lParam(PChar(IntToStr(i)))); SendMessage(FMemoHandle, CM_TEXTCHANGED, 0, 0); |
LittleBen - Do 08.09.11 14:28
Perfekt!!! Vielen Dank, hast mir mal wieder geholfen!
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!