Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi Form.ShowModal im Thread (https://www.delphipraxis.net/104545-form-showmodal-im-thread.html)

gmc616 6. Dez 2007 00:24


Form.ShowModal im Thread
 
Guten Abend DP,

ich fange an mich mit Threads zu beschäftigen. Die ersten paar Threads hab ich auch schon erfolgreich hin gekriegt. So werden in meinem MP3-Player die ID3-Tags in einem Thread ausgelesen und in ein Listview geschrieben. Ob das ganze thread-safe ist weiß ich nicht, aber es funktioniert prima.

Nun möchte ich einen Schritt weiter gehen, und zwar ein Suche-Dialog in einem Thread laufen lassen.

Hintergrund: Auf meinem Hauptfenster wird über einen Timer eine Animation berechnet und dargestellt.
Wenn ich in meinem Suche-Dialog eine Suche starte, animiert meine Animation nicht mehr, da das Suchen die Anwendung blockiert. Klar könnte ich ein ProgressMessages in meine Suche-Funktion einbauen, ist aber nicht Ziel der Sache.

Nun hab ich mir diese Konstruktion in einem Test-Programm zusammen gebastelt.

Delphi-Quellcode:
Type TMyDlgThread = class (TThread)
  private
    FDlg : TMySearchDlg;
    FModalResult : TModalResult;
  public
    Constructor Create(CreateSuspended: Boolean); overload;
    Destructor Destroy (); overload;

    function ShowDlg () : TModalResult;

  protected
    procedure Execute; override;
  end;


constructor TMyDlgThread.Create(CreateSuspended: Boolean);
begin
  inherited;
  self.FreeOnTerminate := false;
  FDlg := TMySearchDlg.Create(nil);
end;

destructor TMyDlgThread.Destroy;
begin
  FDlg.Free;
  inherited;
end;

procedure TMyDlgThread.Execute;
begin
  inherited;
  FModalResult := FDlg.ShowModal;
end;

function TMyDlgThread.ShowDlg: TModalResult;
begin
  Resume;
  WaitFor;
  Result := FmodalResult;
end;
Das ganze endet so, dass mein Suche-Dialog angezeigt wird und dann das ganze Programm stehen bleibt. Nichts geht mehr. Einfach tot, ohne Fehlermeldung und ohne CPU-Last. Nichts!

Was mach ich falsch? Und wie macht man's richtig?

Danke :hi:

Bernhard Geyer 6. Dez 2007 06:02

Re: Form.ShowModal im Thread
 
Alles was mit GUI-Dialogen/Komponenten zu tun hat muss im Hauptthread laufen. Wenn du auf eine Listview zugreifst ohne zu synchonisieren und es läuft hast du zufälligerweise Glück gehabt. Irgendwann wird es auch hier krachen.

gmc616 6. Dez 2007 11:34

Re: Form.ShowModal im Thread
 
Aha. Naja, das muss man natürlich wissen.

Also packt ich nur die Suche-Funktion in ein Thread.

Und wie synchronisiert man das ganze mit einer Listview z.B.?
Was versteht man unter "Thread synchronisieren"? :duck:

Alien426 6. Dez 2007 11:41

Re: Form.ShowModal im Thread
 
Siehe Tutorial.

Bernhard Geyer 6. Dez 2007 12:35

Re: Form.ShowModal im Thread
 
Zitat:

Zitat von gmc616
Aha. Naja, das muss man natürlich wissen.

Wenn du die Unit mit der Thread-Klasse über "Datei/Neu" anlegst schreibt dir Delphi genau diese Probleme + Umschiffung in die Unit als Kommentar hinein.

gmc616 7. Dez 2007 12:36

Re: Form.ShowModal im Thread
 
Hallo,

da ja meine eigentliche Frage beantwortet ist, hätte ich noch eine weitere, eine Letzte, Off-Topic sozusagen.

Ich hab mal 'n Stück zusammen geschrieben und möchte eigentlich nur noch wissen, ob dieser so korrekt ist.
Wenn ja, dann glaube ich das Thema Threads und Synchronisation im Grunde verstanden zu haben und es wird Zeit sich sinnvollen Aufagen für Threads zu widmen.

Delphi-Quellcode:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ComCtrls;

type
  TForm1 = class(TForm)
    Lv: TListView;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);

  private
    { Private-Deklarationen }

  public
    { Public-Deklarationen }

  end;

type TMyThread = class (TThread)
  Private
    FsCap, FsSub1, FsSub2 : string;
    FLv : TListView;
    procedure UpdateListView();
    procedure AddLvItem (ACap,ASub1,ASub2 : string);
  protected
    Procedure Execute (); Override;
  public
    Constructor Create (ALv : TListView);
end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var MyThread : TMyThread;
begin
  MyThread := TMyThread.Create(Lv);
end;

{ TMyThread }

constructor TMyThread.Create(ALv : TListView);
begin
  FreeOnTerminate := false;
  Flv := ALv;
  inherited Create (false);
end;

procedure TMyThread.Execute;
var
  i : integer;
begin
  inherited;

  for i:=0 to 9 do
  begin
    FsCap := 'Cap - ' + inttostr (i);
    FsSub1 := 'Sub1 - ' + inttostr (i);
    FsSub2 := 'Sub2 - ' + inttostr (i);
    Synchronize(UpdateListView);
  end;

  Terminate;
end;

procedure TMyThread.UpdateListView;
begin
  AddLvItem(FsCap,FsSub1,FsSub2);
end;

procedure TMyThread.AddLvItem(ACap, ASub1, ASub2: string);
var
  li : TListItem;
begin
  li := Flv.Items.Add;
  li.Caption := ACap;
  li.SubItems.Add(ASub1);
  li.SubItems.Add(ASub2);

end;

end.
Passt das so?

Danke für eure Geduld. :stupid:

sirius 7. Dez 2007 12:42

Re: Form.ShowModal im Thread
 
Bis auf, dass das Object MyThread nie gelöscht werden kann, da du die Referenz wegschmeisst, ist es ok.
Und terminate solltest du im Thread nicht aufrufen. Terminate wird von außen aufgerufen. Und in einer langen Schleife im Thread solltest du regelmäßig via terminated abfragen ob von außen ein terminate gesetzt wurde und ggf. dann die Schleife abbrechen.

Und du kannst auch (ist kein Fehler, aber ich weis nicht, ob du es bewusst gemacht hast) AddLVItem weglassen und alles in UpdateListview machen.


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