![]() |
Formular in Thread auslagern
Hallo
Hab schon bisschen rumgesucht und auch schon das eine oder andere gefunden, aber bin mir nicht ganz sicher ob das nun funktionieren kann oder nicht. Ich habe in meinem Programm einige Funktionen die halt länger dauern, und möchte nun einen Status anzeigen bzw. so eine Marquee oder so, das der user sieht, ok da tut sich noch was. Da ich aus verschiedenen Probleme heraus dieses längeren Berechnungen nicht in einen Thread auslagern kann/will - möchte ich ein Progressfenster erzeugen,das in einem Thread ausgelagert ist. Diesem Fenster schicke ich dann per Postmessage die Fortschrittsinfos, aber das Progressfenster soll den Fortschritt automatisch anzeigen/zeichnen. Geht soetwas oder bekomme ich da probleme mit der VCL? Ich hätte geplant entweder ein eigenes TApplication Objekt im Thread zu erezugen, oder eine eigene Messageschleife im Thread, bin mir aber ned sicher ob das 100% hinaut (Da so Thread fehler meist nicht immer auftreten ... ) |
AW: Formular in Thread auslagern
Du kannst mit PostMessage problemlos aus dem Thread heraus arbeiten, solange du mit den beiden Parametern auskommst.
Eine besondere Messageschleife oder so etwas ist nicht erforderlich, weil die Abarbeitung im Hauptthread erfolgt. Da PostMessage die Message asynchron verschickt, arbeitet der Thread auch wie sicherlich gewünscht derweil einfach weiter, aber dennoch ohne den Hauptthread zu stören. Der muss nur dann auf die Message reagieren und die GUI entsprechend mit den neuen Werten aktualisieren. |
AW: Formular in Thread auslagern
Wenn ich dich richtig verstanden habe, geht das so nicht! Du kannst lediglich die Berechnung in den Thread auslagern (unter bestimmten Bedingungen gehen auch Datenbankzugriffe). Alle VCL-Zugriffe (z.B. Anzeige des Fortschritts) müssen im Hauptthread stattfinden.
|
AW: Formular in Thread auslagern
Es riecht hier nach Splash-Screen :)
|
AW: Formular in Thread auslagern
Ich sehe es wie Uwe.
Wenn Du Deine Berechnung im Mainthread lässt und in der Funktion (Schleife?) keine Neuzeichnung veranlasst wird sich das Formular nicht neu zeichnen. Du hast wohl nur zwei Möglichkeiten: a) Berechnung in eigenen Thread auslagern und immer mal durch Syncronisize einen Formularfortschritt veranlassen b) komplett im Mainthread bleiben und immer mal Application.ProcessMessages aufrufen. Ansonsten vielleicht noch eine andere Lösung nutzen, wie von Sir Rufo vorgeschlagen. |
AW: Formular in Thread auslagern
Als "Quick and Dirty"-Lösung ist der "Splashscreen" doch vielleicht wirklich nicht so übel. Allerdings bliebe doch weiterhin das Problem dass, wenn jemand auf deine "wirkliche" Anwendung klickt und sie schon 2, 3 Sekunden lang hängt, Windows es zu einem "Ghost Window" macht (ausgrauen, "(Reagiert Nicht)" in der Form-Caption anhängen).
In der gleichen Anwendung quasi eine "zweite VCL" aufmachen habe ich allerdings auch noch nie gesehen (muss allerdings nichts heißen). Ohne mir je ein typisches "Threaded Splashcreen"-Beispiel in Delphi angesehen zu haben würde ich es in eine DLL oder eigene exe auslagern und aus deinem Hauptprogramm musst du mittendrin nur das Fensterhandle wissen, an das du mit PostMessage etwas senden möchtest. Wäre zumindest mein spontaner Gedanke. Aber weiterhin: Die richtige Lösung ist es eh nicht, in der Zeit kann man wahrscheinlich die Arbeit auch vernünftig in einen Thread auslagern und die Oberfläche erst gar nicht einfrieren lassen... |
AW: Formular in Thread auslagern
Mal so ein kleiner Minimalcode:
Delphi-Quellcode:
var
LForm : TForm; LThread : TThread; begin LForm := TSplashScreen.Create( nil ); try LThread := TStartupThread.Create( LForm ); try LForm.ShowModel; LThread.WaitFor; finally LThread.Free; end; finally LForm.Free; end; end;
Delphi-Quellcode:
muss lediglich am Ende eine Nachricht an die Form schicken, damit die geschlossen wird.
TStartupThread
Alles weitere (Progress, Infos, ...) ist Zuckerguss und funktioniert auf die gleiche/ähnliche Art. Das Erzeugen von VCL-Gedöns ausserhalb des MainThread-Context sollte man aber bleiben lassen. |
AW: Formular in Thread auslagern
ShowModal?
Bis zum WaitFor kommt der dann ja nicht, falls nicht jemand vorher das Fenster schließt. Wäre es da nicht andersrum besser?
Delphi-Quellcode:
var
LForm : TForm; LThread : TThread; begin LForm := TSplashScreen.Create(nil); try LThread := TStartupThread.Create(LForm); try LForm.Show; LThread.WaitFor; LForm.Hide; finally LThread.Free; end; finally LForm.Free; end; end; // oder var LForm : TForm; LThread : TThread; begin LThread := TStartupThread.Create; try LForm := TSplashScreen.Create(nil); try LForm.Show; LThread.WaitFor; finally LForm.Free; end; finally LThread.Free; end; end; Wie schon erwähnt, müssen die VCL-Komponenten im Hauptthread VCL-Thread bleiben. Man könnte zwar in anderen Threads direkt via WinAPI Formulare nzeigen, aber diese müssen dann komplett in dem Thread erstellt, behandelt und freigegeben werden, inkl. eigener Message-Loop. |
AW: Formular in Thread auslagern
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:
Delphi-Quellcode:
und das ist bei meiner Variante eben genau nicht der Fall.
LForm.Show;
// Wir befinden uns im MainThread-Context und da tut sich jetzt nichts mehr, bis der Thread abgearbeitet ist LThread.WaitFor; Zitat:
Delphi-Quellcode:
Anwendung im Anhang (kompiliert und als Source)
unit StartupThread;
interface uses FormThreadWait, System.SysUtils, Classes; type TStartupThread = class( TThread ) private FCloseForm : TThreadProcedure; FInfoToForm : TProc<string>; procedure InfoToForm( const AInfo : string ); protected procedure DoExecute; virtual; procedure Execute; override; public constructor Create( AForm : TThreadWaitForm ); end; implementation { TStartupThread } constructor TStartupThread.Create( AForm : TThreadWaitForm ); begin inherited Create( False ); // Anonyme Methode zum Schließen der Form FCloseForm := procedure begin AForm.Close; end; FInfoToForm := procedure( AInfo : string ) begin AForm.Label1.Caption := AInfo; end; end; procedure TStartupThread.DoExecute; var LIdx : Integer; begin InfoToForm( 'Initialisierung...' ); Sleep( 500 ); for LIdx := 1 to 20 do begin InfoToForm( 'Schritt ' + IntToStr( LIdx ) ); Sleep( 250 ); end; end; procedure TStartupThread.Execute; begin inherited; try DoExecute; finally // Form schließen synchronisiert abschicken // Queue würde auch gehen, aber was sollen wir in der Zwischenzeit noch machen, wir sind fertig ;o) Synchronize( FCloseForm ); end; end; procedure TStartupThread.InfoToForm( const AInfo : string ); begin Queue( procedure begin FInfoToForm( AInfo ); end ); end; end. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 01:38 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz