Fenster in einem Thread öffnen

Für alles, was in den übrigen Lazarusthemen keinen Platz, aber mit Lazarus zutun hat.
Antworten
Bernd
Beiträge: 27
Registriert: Mo 11. Jun 2007, 10:12
OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.2.z)
CPU-Target: xxBit

Fenster in einem Thread öffnen

Beitrag von Bernd »

Hallo,
ich versuche ein MessageDlg oder Showmessage Fenster in einem Thread zu öffnen, bekomme aber eine Exception. Wo ist mein Fehler oder gibt es eine andere Lösung?

Hintergrund: Mein Programm läuft als Endlosschleife, wie in den Lazarusbeispielen unter singlethread beschrieben. Es holt Daten von einem externen Messgerät und zeigt sie in einem Diagramm an. Das funktioniert recht gut.
Nun benötige ich eine Anwenderbestätigung ohne den Lauf zu unterbrechen. Ich dachte mir einfach ein MessageDlg oder Showmessage Fenster in einem weiteren Thread öffnen und nach der Bestätigung eine Variable setzen und den Thread beenden.

Code: Alles auswählen

{ TMyThread }
 
procedure TMyThread.ShowStatus;
begin
  Form1.Caption := fStatusText;
  //showmessage('Threadtest');
end;
 
procedure TMyThread.Execute;
begin
  fStatusText := 'TMyThread Starting...';
  Synchronize(@Showstatus);
  //showmessage('Threadtest');
end;
 
constructor TMyThread.Create(CreateSuspended: boolean);
begin
  FreeOnTerminate := True;
  inherited Create(CreateSuspended);
end;               
 
Diesen abgewandelten Code aus den Beispielen wollte ich benutzen.
Wenn ich das Fenster "Showmessage" in der ShowStatus Procedure aktiviere funktioniert das ganze zwar, aber da es durch Synchronize ja eigentlich im Hauptprogramm läuft, steht dieses auch still bis ich reagiert habe. Wenn ich dagegen die Showmessage in den Execute Procedure aktiviere gibt es eine Exception zur Laufzeit.

Konnte im Internet bisher keine Lösung finden

Gruß Bernd

mschnell
Beiträge: 3444
Registriert: Mo 11. Sep 2006, 10:24
OS, Lazarus, FPC: svn (Window32, Linux x64, Linux ARM (QNAP) (cross+nativ)
CPU-Target: X32 / X64 / ARMv5
Wohnort: Krefeld

Re: Fenster in einem Thread öffnen

Beitrag von mschnell »

Es gibt keine Standard-Lösung.

Eine Benutzer-Kommunikation darf nur im Mainthread tattfinden nicht in einem Worker-Thread (deshalb heißt er so).

Im Normalfall sollte man das Projekt so anlegen dass der Mainthread ausschließlich für die Benutzer-Kommunikation berwendet wird und es deshalb nicht schlimm ist, wenn er "steht".

Wenn Du aber während die Message gezeigt wird ein Update auf deiner Benutzeroberfläche machen willst, kannst Du Showmessage nicht verwenden. Dann musst Du eine Form für Deine "Messagebox" kreieren und das mit "show" (nicht "showmodal")aufrufen. Dann läuft die Message-Queue weiter und auf allen Deinen Forms werden Updates dargestellt. (Threads brauchst Du dafür nicht.)

Wenn Du in einem Thread, der durchlaufen soll, Daten-Updates erzeugst, die auf der GUI angezeigt werden sollen, musst Du diese in einfachen Daten-Strukturen hinterlegen und diese mit dem Mainthread anzeigen. Entweder mit Polling (durch einen TTimer) oder indem der Thread dem Mainthread eine Mitteilung in die Message-Queue schickt (dafür gibt es - glaube ich - OS-unabhängige Synchronisations-Objekte)

Für die Datenübergabe vom Main-Thread an einen Thread gilt ähnliches (allerdings hat ein Thread "von selber" keine Message Queue).

Um eine Benutzer-Kommunikation für einem Thread zu machen ist also möglicherweise beides (Daten-Übergabe in beide Richtungen) notwendig.

-Michael

Bernd
Beiträge: 27
Registriert: Mo 11. Jun 2007, 10:12
OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.2.z)
CPU-Target: xxBit

Re: Fenster in einem Thread öffnen

Beitrag von Bernd »

Hallo danke für den Hinweis
Wenn Du aber während die Message gezeigt wird ein Update auf deiner Benutzeroberfläche machen willst, kannst Du Showmessage nicht verwenden. Dann musst Du eine Form für Deine "Messagebox" kreieren und das mit "show" (nicht "showmodal")aufrufen. Dann läuft die Message-Queue weiter und auf allen Deinen Forms werden Updates dargestellt. (Threads brauchst Du dafür nicht.)
Ich werde dies einmal probieren. Hatte mich wohl etwas verrannt.

Gruß Bernd

Bernd
Beiträge: 27
Registriert: Mo 11. Jun 2007, 10:12
OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.2.z)
CPU-Target: xxBit

Re: Fenster in einem Thread öffnen

Beitrag von Bernd »

Ich habe mein Problem gelöst.

Mein "singleThread" läuft und mein Showmessage Fenster legt sich über das Diagramm ohne das der Thread anhält.

Danke Michael für die Erklärung, wieder was gelernt.

So habe ich es gelöst - muss nur noch schön gemacht werden.

Code: Alles auswählen

// ShowMessage ================================================================
 
procedure TForm1.ShowMessage(Msg:String);
var
 MessageForm:TMessageForm;
begin
MessageForm:=TMessageForm.Create(nil);
MessageForm.Label1.Caption:=Msg;
MessageForm.Button1.Caption:='OK';
MessageForm.Caption:='Kalibration';
MessageForm.Show;
end;
 
constructor TMessageForm.Create(AOwner: TComponent);
begin
   inherited Create(AOwner);
   Caption := 'Message Show';
   Width   := 200;
   Height  := 75;
   Left    := 200;
   Top     := 200;
 
   button1 := TButton.Create(Self);
   button1.OnClick := button1click;
   button1.Parent  := Self;
   button1.left    := (width - 85) div 2 ;
   button1.top     := (height - 32) div 2;
   button1.width   := 85;
   button1.height  := 32;
   button1.caption := 'Button1';
   button1.Show;
   Label1          := TLabel.Create(self);
   Label1.Parent   := Self;
   Label1.Left     := 10;
   Label1.Top      := 10;
   Label1.Caption  := 'Label1';
   Label1.Show;
end;
 
procedure TMessageForm.Button1Click(Sender : TObject);
begin
 Form1.kalibration:= true;
 close();
end;
Bernd

Antworten