AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Formular in Thread auslagern

Ein Thema von Gruber_Hans_12345 · begonnen am 3. Feb 2014 · letzter Beitrag vom 3. Feb 2014
Antwort Antwort
Gruber_Hans_12345

Registriert seit: 14. Aug 2004
1.439 Beiträge
 
Delphi 2007 Professional
 
#1

Formular in Thread auslagern

  Alt 3. Feb 2014, 11:24
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 ... )
Gruss Hans

2B or not 2B, that is FF
  Mit Zitat antworten Zitat
Benutzerbild von jaenicke
jaenicke

Registriert seit: 10. Jun 2003
Ort: Berlin
9.582 Beiträge
 
Delphi 11 Alexandria
 
#2

AW: Formular in Thread auslagern

  Alt 3. Feb 2014, 11:28
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.
Sebastian Jänicke
Alle eigenen Projekte sind eingestellt, ebenso meine Homepage, Downloadlinks usw. im Forum bleiben aktiv!
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.453 Beiträge
 
Delphi 12 Athens
 
#3

AW: Formular in Thread auslagern

  Alt 3. Feb 2014, 11:33
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.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#4

AW: Formular in Thread auslagern

  Alt 3. Feb 2014, 11:55
Es riecht hier nach Splash-Screen
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)
  Mit Zitat antworten Zitat
Benutzerbild von stahli
stahli

Registriert seit: 26. Nov 2003
Ort: Halle/Saale
4.343 Beiträge
 
Delphi 11 Alexandria
 
#5

AW: Formular in Thread auslagern

  Alt 3. Feb 2014, 12:27
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.
Stahli
http://www.StahliSoft.de
---
"Jetzt muss ich seh´n, dass ich kein Denkfehler mach...!?" Dittsche (2004)
  Mit Zitat antworten Zitat
Der schöne Günther

Registriert seit: 6. Mär 2013
6.159 Beiträge
 
Delphi 10 Seattle Enterprise
 
#6

AW: Formular in Thread auslagern

  Alt 3. Feb 2014, 12:32
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...
  Mit Zitat antworten Zitat
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#7

AW: Formular in Thread auslagern

  Alt 3. Feb 2014, 13:19
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;
TStartupThread muss lediglich am Ende eine Nachricht an die Form schicken, damit die geschlossen wird.
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.
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu
Online

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.063 Beiträge
 
Delphi 12 Athens
 
#8

AW: Formular in Thread auslagern

  Alt 3. Feb 2014, 13:49
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.
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat,
wird PoSex im Delphi viel seltener praktiziert.

Geändert von himitsu ( 3. Feb 2014 um 13:52 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#9

AW: Formular in Thread auslagern

  Alt 3. Feb 2014, 14:29
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.
Bei deiner Variante wird der MainThread aber blockiert
Delphi-Quellcode:
LForm.Show;
// Wir befinden uns im MainThread-Context und da tut sich jetzt nichts mehr, bis der Thread abgearbeitet ist
LThread.WaitFor;
und das ist bei meiner Variante eben genau nicht der Fall.

TStartupThread muss lediglich am Ende eine Nachricht an die Form schicken, damit die geschlossen wird.
Hier mal so ein Beispiel StartupThread
Delphi-Quellcode:
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.
Anwendung im Anhang (kompiliert und als Source)
Angehängte Dateien
Dateityp: zip dp_178908.zip (809,1 KB, 44x aufgerufen)
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 15:27 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