Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Einfacher thread der nur ein MessageDlg anzeigt erzeugen (https://www.delphipraxis.net/126843-einfacher-thread-der-nur-ein-messagedlg-anzeigt-erzeugen.html)

Kostas 3. Jan 2009 13:34


Einfacher thread der nur ein MessageDlg anzeigt erzeugen
 
Hallo Zusammen,

zunächst einmal ein gutes Neues Jahr ans Forum.

ich habe mich mit threads noch nicht beschäftigt.
Könnt Ihr mir bitte helfen ein thread zu erzeugen der nicht anderes tut als ein
MessageDlg zu erzeugen. Der Hintergrund ist, an der aufrufenden Stelle können
mehrere MessageDlg erzegut werden und der code soll jedoch sofort weiterlaufen.
Der Anwender soll in Ruhe alle MessageDlg lesen und bestätigen können.

Im Forum gibt es eine Menge über threads. Wenn man damit nicht gearbeitet hat,
weis man nichteinmal nach was man suchen muss.

Gruß Kostas

SirThornberry 3. Jan 2009 13:42

Re: Einfacher thread der nur ein MessageDlg anzeigt erzeugen
 
Ein MessageDlg in einem Thread wird nicht funktionieren da die VCL nicht Threadsave ist. Wenn dann müsstest du MessageBox oder eine andere Api-Funktion verwenden. An welcher Stelle genau kommst du nicht weiter und hast du dir schon entsprechende Threadtutorials angesehen? Auch bei Delphi müsste eines dabei sein (zwar kein Tutorial aber ein Beispiel).

Kostas 3. Jan 2009 16:12

Re: Einfacher thread der nur ein MessageDlg anzeigt erzeugen
 
Zitat:

Zitat von SirThornberry
Ein MessageDlg in einem Thread wird nicht funktionieren da die VCL nicht Threadsave ist. Wenn dann müsstest du MessageBox oder eine andere Api-Funktion verwenden. An welcher Stelle genau kommst du nicht weiter und hast du dir schon entsprechende Threadtutorials angesehen? Auch bei Delphi müsste eines dabei sein (zwar kein Tutorial aber ein Beispiel).

Sehr interessant das die VCL nicht Threadsave ist!
Ich habe mir noch nichts angeschaut weil das ein sehr umfangreiches und kompliziertes Thema ist.
Ich kenne leider auch nicht die Zusammenhänge wann etwas nicht Threadsave ist. Wann immer ich
eine ähnliche funktionalität benötigt habe, habe ich einfach einen Timer verwendet der mit die
enstprechende Funktion aufgerufen hat. Nach Threadtutorials werde ich sogleich mal suchen.

Gruß Kostas

Kostas 3. Jan 2009 17:23

Re: Einfacher thread der nur ein MessageDlg anzeigt erzeugen
 
Hallo SirThornberry,

Über die Delphi Vorlage habe ich mit ein Threadrumpf erzeugen lassen
und ausgeführt. Es wird leider nichts angezeigt. Möglicherweise
hat es was mit ShowMessage zu tun es kommt ja auch aus der VCL.
Zumindest würde ich einen Fehler erwarten, es kommt jedoch nichts.

Hast Du eine Idee?



Delphi-Quellcode:
unit MessageBoxThread;

interface

uses
  Classes, Dialogs;

type
  TMessageBoxThread = class(TThread)
  private
    { Private-Deklarationen }
  protected
    text: string;
    procedure Execute; override;
  public
    constructor Create(msg:string);
  end;

implementation

{ TMessageBoxThread }

constructor TMessageBoxThread.Create(msg:String);
begin
  inherited Create(false);
  text := msg;
  ShowMessage(text); // es passiert nichts
end;

procedure TMessageBoxThread.Execute;
begin
  { Thread-Code hier plazieren }
  ShowMessage(text); // es passiert nichts

end;

end.
Und so sieht der Aufruf des Threads aus:

Delphi-Quellcode:
var ThreadMB: TMessageBoxThread;
begin
  ...
      ThreadMB := TMessageBoxThread(s);
      ThreadMB.Priority := tpLower;
      ThreadMB.Resume;

jbg 3. Jan 2009 17:33

Re: Einfacher thread der nur ein MessageDlg anzeigt erzeugen
 
Zitat:

ThreadMB := TMessageBoxThread(s)
Wo steht denn hier das "Create" :wink:

Zitat:

Delphi-Quellcode:
procedure TMessageBoxThread.Execute;
begin
  { Thread-Code hier plazieren }
  ShowMessage(text); // es passiert nichts
end;

Lese dir mal den Roman, den Delphi als Kommentar vor der Thread Klasse hingeschrieben hat, genau durch.

DevidEspenschied 3. Jan 2009 17:58

Re: Einfacher thread der nur ein MessageDlg anzeigt erzeugen
 
Man kann aus der Execute-Methode nichts direkt von der VCL aufrufen, und dazu gehört auch ShowMessage. Du must im Protected-Abschnitt eine eigene Procedure deklarieren, die wiederum ShowMessage aufruft:

Delphi-Quellcode:
TMessageBoxThread = class(TThread)
  private
    { Private-Deklarationen } 
  protected
    text: string;
    procedure Execute; override;
    procedure StarteThread; virtual; abstract;
  public
    constructor Create(msg:string);
  end;
In der Execute-Methode erscheint nur folgendes:

Delphi-Quellcode:
procedure TMessageBoxThread.Execute;
begin
  Synchronize(StarteThread);
end;
und in der StarteThread-Methode der eigentliche Aufruf von ShowMessage:

Delphi-Quellcode:
procedure TMessageBoxThread.StarteThread;
begin
  ShowMessage(text);
end;
Probiere das mal aus.

Kostas 3. Jan 2009 22:01

Re: Einfacher thread der nur ein MessageDlg anzeigt erzeugen
 
Hallo Zusammen,

tausend Dank, genau so gehts.

Einen schönen Abend noch.

Gruß Kostas

Cyf 4. Jan 2009 04:28

Re: Einfacher thread der nur ein MessageDlg anzeigt erzeugen
 
Bedenke aber, was dabei passiert. Es funktioniert zwar und ist für die VCL auch sinnvoll, jedoch wird der Befehl eben auch entsprechend im Hauptthread ausgeführt.

Die Muhkuh 4. Jan 2009 10:25

Re: Einfacher thread der nur ein MessageDlg anzeigt erzeugen
 
Nimm eine MessageBox, die ist threadsafe.

Kostas 4. Jan 2009 16:03

Re: Einfacher thread der nur ein MessageDlg anzeigt erzeugen
 
Zitat:

Zitat von Die Muhkuh
Nimm eine MessageBox, die ist threadsafe.

Hallo,

ich habe jetz eine entdeckung gemacht.
Zum testen werden zwei threads hintereinander erzeugt und ausgeführt.
Wenn ich Procedure StarteThread ShowMessage verwende, werde sofort zwei Fenster mit
der Nachricht erzeugt. Verwende ich jedoch MessageBox, wird die erte Nachticht erzeugt
und sobald ich sie bestätigt habe wird die zweite angezeigt. Ich habe das Fenster
verschoben es ist also nicht direkt hinterhalb. Als ob der erste Thread warten würde
bis der vorherige fertig ist. Kann man das irgendwie erkleren?

Dass zweite was micht interessieren würde ist, ob es Möglich ist den PChar Buffer
für die MesageBox mit dynamischer Länge anzulegen.
Buffer: array [0..MAX_BUFFER] of char;

so geht es nicht:
Buffer: array of char;
SetLength(Buffer,Length(MeinString));




Delphi-Quellcode:
      ThreadMB := TMessageBoxThread.Create(s);
      ThreadMB.Priority := tpLower;
      ThreadMB.Resume;

      ThreadMB := TMessageBoxThread.Create(s);
      ThreadMB.Priority := tpLower;
      ThreadMB.Resume;
Delphi-Quellcode:
unit MessageBoxThread;

interface

uses
  Classes, Dialogs, Forms, Sysutils, Windows;

type
  TMessageBoxThread = class(TThread)
  private
    { Private-Deklarationen }
  protected
    text: string;
    procedure Execute; override;
    procedure StarteThread; virtual; //abstract;
  public
    constructor Create(msg:string);
  end;


implementation

{ TMessageBoxThread }

constructor TMessageBoxThread.Create(msg:String);
begin
  inherited Create(false);
  text := msg;
end;


procedure TMessageBoxThread.Execute;
begin
  Synchronize(StarteThread);
end;

procedure TMessageBoxThread.StarteThread;
const MAX_BUFFER = 500;
var Buffer: array [0..MAX_BUFFER] of char;

begin
  ShowMessage(text);
//  StrLCopy(Buffer, PChar(text), MAX_BUFFER);
//  Application.MessageBox(Buffer, 'Fingerabdruck gefunden', MB_OK);
end;

end.
Gruß Kostas

quendolineDD 4. Jan 2009 16:13

Re: Einfacher thread der nur ein MessageDlg anzeigt erzeugen
 
Erstmal ist MessageBox im Gegensatz zu ShowMessage eine Funktion und keine Prozedur.
Das MessageBox in TApplication ist nur ein Wrapper für die WinAPI Funktion MessageBox.

Das bei MessageBox gewartet wird, bis der Benutzer eine Eingabe macht, resultiert wohl daraus, das erst nach dem Klicken auf eine der Schaltflächen (bei dir mbOK - was auch Standard ist und somit gar nicht übergeben werden müsste) die Funktion zum Programm zurückkehrt. Im Gegensatz dazu ist ShowMessage ein einfaches Anzeigefenster.

jfheins 4. Jan 2009 16:14

Re: Einfacher thread der nur ein MessageDlg anzeigt erzeugen
 
Zitat:

Zitat von Kostas
Delphi-Quellcode:
      ThreadMB := TMessageBoxThread.Create(true);
      ThreadMB.Priority := tpLower;
      ThreadMB.Resume;

      ThreadMB := TMessageBoxThread.Create(true);
      ThreadMB.Priority := tpLower;
      ThreadMB.Resume;
Delphi-Quellcode:
unit MessageBoxThread;

interface

uses
  Classes, Dialogs, Forms, Sysutils, Windows;

type
  TMessageBoxThread = class(TThread)
  private
    { Private-Deklarationen }
  protected
    text: string;
    procedure Execute; override;
    procedure StarteThread; virtual; //abstract;
  public
    constructor Create(msg:string);
  end;


implementation

{ TMessageBoxThread }

constructor TMessageBoxThread.Create(msg:String);
begin
  inherited Create(false);
  text := msg;
end;


procedure TMessageBoxThread.Execute;
begin
  {Windows.}MessageBox(nil, 'Hallo Welt', 'Schöner Text', MB_OK);
end;

end.

Mit MSDN-Library durchsuchenMessageBox brauchst du das nicht mehr synchronisieren, da es ja Threadsafe ist ;)

Aber wirklich die Windows-API-Funktion verwenden und nicht die VCL-Version Application.Messagebox()

Du brauchst übrigens keine Variable im Konstruktor des Threads, du kannst einfach true reinschreiben ;)

Kostas 4. Jan 2009 16:49

Re: Einfacher thread der nur ein MessageDlg anzeigt erzeugen
 
Zitat:

Zitat von jfheins
...
Du brauchst übrigens keine Variable im Konstruktor des Threads, du kannst einfach true reinschreiben ;)

Hallo Julius,

was könntest Du damit meinen?
Dem Constructor übergebe ich nur den Text welcher angezeit werden soll.
Aber vermutlich meinst Du etwas anderes.

Gruß Kostas

jfheins 4. Jan 2009 17:03

Re: Einfacher thread der nur ein MessageDlg anzeigt erzeugen
 
Delphi-Quellcode:
      ThreadMB := TMessageBoxThread.Create(true);
Das da meine ich - ist aber nicht so wichtig ;)

Kostas 4. Jan 2009 17:17

Re: Einfacher thread der nur ein MessageDlg anzeigt erzeugen
 
Zitat:

Zitat von jfheins
Delphi-Quellcode:
      ThreadMB := TMessageBoxThread.Create(true);
Das da meine ich - ist aber nicht so wichtig ;)

Ah, ich verstehe. Das war eigentlich Absicht um den Text der angezeigt werden soll
zu übergeben. Du meinst, es währe besser eine public property zu erzeugen und nach dem Create
über das property den Text zuweisen?

[edit]

ach jetzt sehe ich das gerade.
Ich mache das eigentlich so:

Delphi-Quellcode:
ThreadMB := TMessageBoxThread.Create(s);
      ThreadMB.Priority := tpLower;
      ThreadMB.Resume;

      ThreadMB := TMessageBoxThread.Create(s);
      ThreadMB.Priority := tpLower;
      ThreadMB.Resume;
und nicht so:
Wie das Create umgestellt wurde ist mir ein Rätsel.
Delphi-Quellcode:
ThreadMB := TMessageBoxThread.Create(true);
      ThreadMB.Priority := tpLower;
      ThreadMB.Resume;

      ThreadMB := TMessageBoxThread.Create(true);
      ThreadMB.Priority := tpLower;
      ThreadMB.Resume;
Gruß Kostas

jfheins 4. Jan 2009 22:03

Re: Einfacher thread der nur ein MessageDlg anzeigt erzeugen
 
Ok, hab mich vertan :oops:

Ich hatte nicht gesehen, dass du den Konstruktor überschrieben hast ...

Aber wenn ich mich recht errinere, ist der Orginal-Parameter CreateSuspended - d.h. insb. dass du den Thread sofort nach dem Kontruktor startest weil du ja false übergibst - danach darfst du eigenlich keine Propertys mehr ändern, weil der Thread schon beendet sein könnte !

Da du ja sowiso am Ende ein Resume machst, kannst du also auch true übergeben.

Generell solltest du dich für einen Weg entscheiden: Alles im Konstruktor mitgeben und sofort loslegen oder den Thread schlafend erstellen und dann Properties belegen ;)

Kostas 4. Jan 2009 22:14

Re: Einfacher thread der nur ein MessageDlg anzeigt erzeugen
 
Zitat:

Zitat von jfheins
Ok, hab mich vertan :oops:

..
Generell solltest du dich für einen Weg entscheiden: Alles im Konstruktor mitgeben und sofort loslegen oder den Thread schlafend erstellen und dann Properties belegen ;)

Wie müsste ich bitte den Tread umbauen so das er sofort nach dem erzeugen startet?
Ich würde gerne dem Constructor den Text übergeben und danach kann er auch sofort losgehen.

Und noch eine Kleinigkeit wenn ich darf: Den Buffer habe ich großzügig mit 500 byte angelegt.
Eigentlich würde ich gerne der Buffer zur Laufzeit ermitteln und setzen.
So geht es leider nicht, hast Du eine Idee?

Buffer: array of char;
SetLength(Buffer, Length(s));




Delphi-Quellcode:
procedure TMessageBoxThread.Execute;
const MAX_BUFFER = 500;
var Buffer: array [0..MAX_BUFFER] of char;
begin
  StrLCopy(Buffer, PChar(text), MAX_BUFFER);
  windows.MessageBox(handle, Buffer, 'Fingerabdruck gefunden', MB_OK);
end;
Gruß Kostas

jfheins 4. Jan 2009 22:33

Re: Einfacher thread der nur ein MessageDlg anzeigt erzeugen
 
Das tut er doch bereits :gruebel:
Delphi-Quellcode:
constructor TMessageBoxThread.Create(msg:String);
begin
  inherited Create(false);
  text := msg;
  Priority := tpLower;
end;
Nur darfst du dann keine Properties mehr setzten nachdem du den kOnstruktor aufgerufen hast ...

Zu dem Char-Array-Pronblem: Schonmal versucht, den String einfach nach PChar zu casten?

Kostas 4. Jan 2009 22:50

Re: Einfacher thread der nur ein MessageDlg anzeigt erzeugen
 
Zitat:

Zitat von jfheins
Das tut er doch bereits :gruebel:
Delphi-Quellcode:
constructor TMessageBoxThread.Create(msg:String);
begin
  inherited Create(false);
  text := msg;
  Priority := tpLower;
end;
Nur darfst du dann keine Properties mehr setzten nachdem du den kOnstruktor aufgerufen hast ...

Zu dem Char-Array-Pronblem: Schonmal versucht, den String einfach nach PChar zu casten?

oh je, natürlich funkt es, ich dachte ich muss Resume immer aufrufen.
Das mit PChar war das erste was ich probiert hatte. Zu dem Zeitpunkt hat es jedoch
Fehlermeldungen geregnet, allerding nicht wegen cast auf PChar wie ich soeben gemerkt
habe. Auch das geht also. So gefehlt mir das.

Tausend Dank Julius Du warst mir eine große Hilfe.

Gruß Kostas

Delphi-Quellcode:
unit MessageBoxThread;

interface

uses
  Classes, Dialogs, Forms, Sysutils, Windows;

type
  TMessageBoxThread = class(TThread)
  private
    { Private-Deklarationen }
  protected
    text: string;
    procedure Execute; override;
  public
    constructor Create(msg:string);
  end;


implementation

{ TMessageBoxThread }

constructor TMessageBoxThread.Create(msg:String);
begin
  inherited Create(false);
  text := msg;
  Priority := tpLower;
end;


procedure TMessageBoxThread.Execute;
begin
  windows.MessageBox(handle, Pchar(text), 'Fingerabdruck gefunden!', MB_OK);
end;


end.
Aus dem Aufruf ist jetzt nur noch das übrichgeblieben. :-)
Delphi-Quellcode:
ThreadMB := TMessageBoxThread.Create(s);


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