Delphi-PRAXiS
Seite 2 von 2     12   

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi Form in neuem Thread laufen lassen (https://www.delphipraxis.net/192420-form-neuem-thread-laufen-lassen.html)

Delphi-Laie 24. Apr 2017 13:40

AW: Form in neuem Thread laufen lassen
 
Zitat:

Zitat von TiGü (Beitrag 1368871)
Ist doch total simpel?
Einfach im Thread die entsprechend gewünschten Windowsfunktionen aufrufen?

Anscheinend ja, wenn man weiß, wie es geht. Oder einfach in den VCL-Quelltexten diese Funktionalitäten "ausgraben" und - das Urheberrecht beachtend - übernehmen.

Vielen Dank!

jus 25. Apr 2017 22:57

AW: Form in neuem Thread laufen lassen
 
Zitat:

Zitat von Zacherl (Beitrag 1368770)
Zitat:

Zitat von jus (Beitrag 1368766)
braucht man die überhaupt? :gruebel:

Ja, die brauchst du in jedem Falle. Aber ist das
Delphi-Quellcode:
IsDialogMessage
notwendig? Glaube das kannst du weglassen.

@Zacherl: Danke, ok, das IsDialogMessage habe ich mal rausgenommen.

Ich bräuchte bitte wieder eure Hilfe. Ich bin auf ein seltsames Problem gestossen, und zwar lasse ich mir die Anzahl der Durchläufe vom Thread über OutputDebugString anzeigen.
Delphi-Quellcode:
procedure TDataThread.Execute;
var
  Msg: TMsg;
  i: Cardinal;
begin
  hdlg := CreateDialog(HInstance, MAKEINTRESOURCE(100), Self.Handle, @DlgFunc);
  ShowWindow(hdlg, SW_SHOW);

  i := 0;
  while not terminated do
  begin
    BERECHNE_WAS; // <-------------- ich würde hier gerne was berechnen lassen
    if GetMessage(msg,0,0,0) then
    begin
      TranslateMessage(Msg);
      DispatchMessage(Msg);
    end;
    OutputDebugString(PChar('i: '+IntToStr(i)));
    inc(i);
  end;
end;
Das komische daran ist, dass der Thread stehen bleibt, wenn ich auf ein anderes VCL Fenster von Hauptthread wechsle, sprich in meinem Falle auf Form1 von Unit1.pas klicke. Es scheint so zu sein, dass beim Focusverlust der Thread einfach stehen bleibt, weil er nichts mehr zu tun hat. Sobald ich das NonVclThread Fenster bewege oder einfach mit der Maus drüberfahre, läuft die Nachrichtenschleife zwischen "while not terminated do" wieder weiter. Der GUI macht das überhaupt nichts aus. Aber das Problem ist ja, wenn ich dann irgendwelche Berechnungen im gleichen Thread erledigen möchte, geht das dann nicht, sprich ich bräuchte da einen zusätzlichen Thread, wo die Berechnungen erledigt werden und mache die GUI Anzeigesachen in diesem Thread. Ist das so, oder gibt es dazu eine elegantere Lösung? :gruebel:
Eine schlechte Lösung, was ich schon ausprobiert habe, wäre, dass ich mit einer SendMessage in der Schleife dem Thread zwinge weiter zu machen. Was aber auffällt ist, dass anscheinend nicht mehr als ca.30-40 Mal pro Sekunde die While-Schleife durchlaufen wird, was eine erbärmliche Performance ist. :-(

jaenicke 26. Apr 2017 03:21

AW: Form in neuem Thread laufen lassen
 
Siehe Doku von GetMessage...
https://msdn.microsoft.com/de-de/lib...(v=vs.85).aspx
Zitat:

The function dispatches incoming sent messages until a posted message is available for retrieval.
Was du brauchst ist PeekMessage, denn das kehrt direkt zurück und nicht erst wenn eine Message geholt werden konnte.

Allerdings macht ein weiterer Thread durchaus Sinn. Denn sonst blockiert deine Berechnung ja wieder die GUI.

BrightAngel 26. Apr 2017 06:47

AW: Form in neuem Thread laufen lassen
 
Siehe auch meinen Beitrag #29 in diesem Thread dazu :)

Brighty

jus 27. Apr 2017 00:04

AW: Form in neuem Thread laufen lassen
 
Zitat:

Zitat von BrightAngel (Beitrag 1369090)
Siehe auch meinen Beitrag #29 in diesem Thread dazu :)
Brighty

@Brighty: ups, sorry, habe dein Link übersehen, :oops: Da steht ja genau das drin, was jaenicke erklärt hat, habe ich mir gleich in Evernote gespeichert. :-D

@jaenicke: Danke für den Tipp! :thumb: Jetzt habe ich aber Gewissheit, dass ich vermutlich meine Berechnungen in einem 2. Thread reingeben soll.

Ich hätte aber im Falle von Peekmessage einfach die Nachrichtenschleife wie folgt gebaut und scheint auch zu funktionieren:
Delphi-Quellcode:
procedure TDataThread.Execute;
var
  Msg: TMsg;
begin
  hdlg := CreateDialog(HInstance, MAKEINTRESOURCE(100), Self.Handle, @DlgFunc);
  ShowWindow(hdlg, SW_SHOW);

  while not terminated do
  begin
    BERECHNE_WAS; // <-------------- ich würde hier gerne was berechnen lassen
    if PeekMessage(msg, hdlg, 0, 0, PM_REMOVE) then
      begin
        TranslateMessage(Msg);
        DispatchMessage(Msg);
      end;
  end;
end;
Laut MS Doku in C ist aber gar kein TranslateMessage und DispatchMessage mehr drin.
Code:
fDone = FALSE;
while (!fDone)

    fDone = DoLengthyOperation(); // application-defined function
 
    // Remove any messages that may be in the queue. If the
    // queue contains any mouse or keyboard
    // messages, end the operation.
 
    while (PeekMessage(&msg, hwnd, 0, 0, PM_REMOVE))
    { 
        switch(msg.message)
        { 
            case WM_LBUTTONDOWN:
            case WM_RBUTTONDOWN:
            case WM_KEYDOWN:
                // 
                // Perform any required cleanup.
                // 
                fDone = TRUE;
        } 
    } 
}
Meine Frage wäre aber, wenn ich Peekmessage verwenden möchte, soll ich dann TranslateMessage u. DispatchMessage nicht verwenden, oder kann ich weiterhin TranslateMessage u. DispatchMessage verwenden, wie ich es in vorigen Delphicode gemacht habe?

lg,
jus

HolgerX 27. Apr 2017 04:32

AW: Form in neuem Thread laufen lassen
 
Hmm..

Wenn ich in Threads Windows-Messages verarbeiten lassen will, habe ich mir hierfür ein ProcessMessage nachgebaut:

Delphi-Quellcode:
type
  TThreadTerminateBreak = class (TThread);

procedure ThreatProcessRequests(AThread : TThread; WaitForMessage: Boolean);
var
  msg: TMsg;
  Rslt: Boolean;
begin
  while True do
  begin
    if TThreadTerminateBreak(AThread).Terminated and WaitForMessage then break;
    if WaitForMessage then
      Rslt := GetMessage(msg, 0, 0, 0)
    else
      Rslt := PeekMessage(msg, 0, 0, 0, PM_REMOVE);
    if not Rslt then break;
    DispatchMessage(msg);
    Sleep(1);
  end;
end;
Das TranslateMessage ist ja nur für die Konvertierung von Key-Events hilfreich, bei anderen Messages wird es jedoch nicht gebraucht.

Michael II 27. Apr 2017 13:27

AW: Form in neuem Thread laufen lassen
 
Hallo jus

wenn du dein BERECHNE_WAS; in einen weiteren Thread t2 auslagerst, dann kannst du in deinem jetzigen Thread t1 in den meisten Fällen weiterhin GetMessage verwenden. Es macht ja durchaus Sinn, wenn t1 nix tut, wenn t1 nix zu tun hat.

BERECHNE_WAS;: nur in t1 belassen, wenn BERECHNE_WAS; sehr kurz rechnet, sonst blockierst du nun einfach t1 statt wie früher mit einem VCL Fenster den Hauptthread... ;-).

Und noch eine kleine Verbesserungsmöglichkeit. Du hast zuletzt diesen Code veröffentlicht:

Delphi-Quellcode:
while not terminated do
begin
 BERECHNE_WAS; // <-------------- ich würde hier gerne was berechnen lassen
 if PeekMessage(msg, hdlg, 0, 0, PM_REMOVE) then
 begin
  TranslateMessage(Msg);
  DispatchMessage(Msg);
 end;
end;


Verwende besser while PeekMessage anstatt if. Mit if kann dein Thread immer jeweils nur eine Windowsmeldung abarbeiten und muss danach wieder BERECHNE_WAS; ausführen. Viele Windowsmeldungen in der Warteschlange oder längere Ausführungszeiten von BERECHNE_WAS; wären bei Verwendung von if... also nicht gut für dein Fenster.

jus 28. Apr 2017 00:56

AW: Form in neuem Thread laufen lassen
 
Zitat:

Zitat von Michael II (Beitrag 1369309)
...
Verwende besser while PeekMessage anstatt if. Mit if kann dein Thread immer jeweils nur eine Windowsmeldung abarbeiten und muss danach wieder BERECHNE_WAS; ausführen. Viele Windowsmeldungen in der Warteschlange oder längere Ausführungszeiten von BERECHNE_WAS; wären bei Verwendung von if... also nicht gut für dein Fenster.

Ok, Danke für den Hinweis mit der "if PeekMessage", wieder mal was gelernt. Ich werde wahrscheinlich dieses BERECHNE_WAS; in einen 2.Thread packen.

lg,
jus

jus 29. Apr 2017 02:06

AW: Form in neuem Thread laufen lassen
 
Liste der Anhänge anzeigen (Anzahl: 3)
Zitat:

Zitat von jaenicke (Beitrag 1368035)
...
Aber da steckt eigentlich nicht viel dahinter, wenn man es richtig macht.

Das Fenster selbst steckt ja in einer Ressource. Das schöne ist nun, dass nach der Anzeige eines solchen Fensters dessen Controls ja alle da sind. Man findet die also direkt.

Die Klasse für solch einen Dialog ist nun von TThread abgeleitet. Beim Start des Threads zeigt der das Fenster mit ShowWindow an. Danach findet man mit EnumChildWindows die Controls, wobei als Userpointer einfach der eigene Dialog angegeben ist. So bekommt die Threadinstanz einen Methodenaufruf pro gefundenem Control.

Mit GetClassName bekommt man nun den Typ des Controls heraus und erstellt eine passende Wrapperklasse, alle abgeleitet von einer Basisklasse. Die Instanz kann man sich dann direkt merken um über die ID an die entsprechende Wrapperinstanz zu kommen.

Das Basiscontrol braucht sich nur das Fensterhandle usw. zu merken. Und ein Wrapper für ein Edit-Control muss eine property Text haben, die auf WM_GETTEXT, SetDlgItemText usw. geht.

Möchte mal meine spartanische Machbarkeitsstudie von jaenicke's obiger Beschreibung mal reinstellen, wo ein Dialog-Form in einem eigenen Thread unabhängig vom VCL Hauptthread läuft. Habe das komplette Projekt auch als Zip-Anhang angehängt. Vielleicht kanns ja wer mal brauchen. Danke nochmals an alle Helfer! :thumb:
Was drinnen noch fehlt sind die Wrapper für die Controls.

Die folgende Unit1.pas ist die normale VCL.
Delphi-Quellcode:
unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    Button1: TButton;
    ProgressBar1: TProgressBar;
    Button2: TButton;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
  i,j: Integer;
begin
  for I := 0 to 50000 do
  begin
    for j := 0 to 100 do progressBar1.Position:=j;
  end;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  DialogThread.Show;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  DialogThread := TDialogThread.Create;
  WorkerThread := TWorkerThread.Create;
end;

end.


Die folgende Unit2.pas enthält 2 Threads, TDialogThread und TWorkerThread. TDialogThread ist für die Anzeige des eigenständigen ThreadDialogs zuständig. TWorkerThread berechnet beispielhaft irgendwas und zeigt dann die Ergebnisse in ThreadDialog an.
Delphi-Quellcode:
unit Unit2;

interface

uses classes, windows, Messages,SysUtils;
type
  TDialogThread = class(TThread)
  private
    hdlg: DWORD ;
  protected
    procedure Execute; override;
  public
    constructor Create;
    procedure Show;
    procedure MemoAdd(s:String);
    procedure ProgressBarPosition(Pos: Integer);
    class function GetCompnentHandleByID(ID: Integer): DWORD;
  end;

  TWorkerThread = class(TThread)
  private
    procedure BerechneWas;
  protected
    procedure Execute; override;
  public
    constructor Create;
  end;

  RComponentList = record
    ID: Integer;
    ClassName: String;
    Name: String;
    Handle: DWORD;
  end;
  ARComponentList = array of RComponentList;

  function dlgfunc(hwnd: hwnd; umsg: dword; wparam: wparam; lparam: lparam): bool; stdcall;

var
  ThreadComponentList: ARComponentList;
  DialogThread: TDialogThread;
  WorkerThread: TWorkerThread;

implementation

uses CommCtrl;

{$R main.res} //hier kommt die Dialogresource rein

function dlgfunc(hwnd: hwnd; umsg: dword; wparam: wparam; lparam: lparam): bool; stdcall;
var
  ProgressHandle:DWORD;
begin
  result := true;
  case umsg of
    WM_CLOSE:
      EndDialog(hWnd, 0);
    WM_DESTROY:
      PostQuitMessage(0);
    WM_COMMAND:
      if hiword(wparam) = BN_CLICKED then begin
        case loword(wparam) of
          IDOK:
            begin
              messagebox(hwnd, PChar('OK Button gedrückt. '+IntToStr(ProgressHandle)), 'Meldung', 0);
            end;
        end;
      end;
  else result := false;
  end;
end;

function EnumChildProc(const AhWindow : DWORD;const ADummy : PDWORD) : Boolean; stdcall;
var
  pBuffer : PChar;
  dwSize : DWORD;

begin
  SetLength(ThreadComponentList, Length(ThreadComponentList)+1);
  Result := true;
  dwSize := 255;
  pBuffer := AllocMem(dwSize);
  try
    if GetClassName(AhWindow,pBuffer,dwSize) = 0 then
    begin
      exit;
    end;
    ThreadComponentList[High(ThreadComponentList)].ID := GetDlgCtrlID(AhWindow);
    ThreadComponentList[High(ThreadComponentList)].ClassName := StrPas(pBuffer);
    ThreadComponentList[High(ThreadComponentList)].Handle := AhWindow;
  finally
    FreeMem(pBuffer,dwSize);
  end;
end;


{ TDialogThread }

constructor TDialogThread.Create;
begin
  inherited Create(False);
  FreeOnTerminate := TRUE;
end;

procedure TDialogThread.Execute;
var
  Msg: TMsg;
  ProgressHandle: DWORD;

begin
  hdlg := CreateDialog(HInstance, MAKEINTRESOURCE(100), Self.Handle, @DlgFunc);
  ShowWindow(hdlg, SW_SHOW);

  //hole mal alle Komponenten
  EnumChildWindows(hdlg,@EnumChildProc,0);

  ProgressHandle := GetCompnentHandleByID(3000);
  if ProgressHandle>0 then
  begin
    SendMessage(ProgressHandle,PBM_SETRANGE,0,MAKELPARAM(0,100)); //Setze den Bereich von ProgressBar auf 0..100
    SendMessage(ProgressHandle,PBM_SETSTEP,1,0); //Setze den Bereich von ProgressBar auf 0..100
  end;

  while not terminated do
  begin
    if GetMessage(msg,0,0,0) then
    begin
      TranslateMessage(Msg);
      DispatchMessage(Msg);
    end;
  end;
end;

class function TDialogThread.GetCompnentHandleByID(ID: Integer): DWORD;
var
  i: Integer;
begin
  result:=0;
  if Length(ThreadComponentList)<1 then exit;
  for i := 0 to High(ThreadComponentList) do
  begin
    if ThreadComponentList[i].ID = ID then
    begin
      result := ThreadComponentList[i].Handle;
      break;
    end;
  end;
end;

procedure TDialogThread.MemoAdd(s: String);
var
  MemoHandle: DWORD;
  MemoCount: Integer;
  SelStart, LineLen: Integer;
  Line: string;
begin
  MemoHandle := GetCompnentHandleByID(4001);
  if MemoHandle>0 then
  begin
    //Bestimme die Count Anzahl
    MemoCount := SendMessage(MemoHandle, EM_GETLINECOUNT, 0, 0);
    if SendMessage(MemoHandle, EM_LINELENGTH, SendMessage(MemoHandle, EM_LINEINDEX, MemoCount - 1, 0), 0) = 0 then Dec(MemoCount);
    if MemoCount >= 0 then
    begin
      SelStart := SendMessage(MemoHandle, EM_LINEINDEX, MemoCount, 0);
      if SelStart >= 0 then Line := S + #13#10 else
      begin
        SelStart := SendMessage(MemoHandle, EM_LINEINDEX, MemoCount - 1, 0);
        if SelStart < 0 then Exit;
        LineLen := SendMessage(MemoHandle, EM_LINELENGTH, SelStart, 0);
        if LineLen = 0 then Exit;
        Inc(SelStart, LineLen);
        Line := #13#10 + s;
      end;
      SendMessage(MemoHandle, EM_SETSEL, SelStart, SelStart);
      SendMessage(MemoHandle, EM_REPLACESEL, 0, Longint(PChar(Line)));
    end;
  end;
end;

procedure TDialogThread.ProgressBarPosition(Pos: Integer);
var
  ProgressHandle: DWORD;
begin
  ProgressHandle := GetCompnentHandleByID(3000);
  if ProgressHandle>0 then
  begin
    SendMessage(ProgressHandle, PBM_SETPOS, Pos, 0);
  end;
end;

procedure TDialogThread.Show;
begin
  ShowWindow(hdlg, SW_SHOW);
end;


{ TWorkerThread }

procedure TWorkerThread.BerechneWas;
begin
  Sleep(800);
end;

constructor TWorkerThread.Create;
begin
  inherited Create(TRUE);
  FreeOnTerminate := TRUE;
  Resume;
end;

procedure TWorkerThread.Execute;
var
  i: Integer;
begin
  inherited;
  i:=0;
  while not terminated do
  begin
    BerechneWas;
    DialogThread.MemoAdd('Test'+IntToStr(i));
    if i<=100 then
    begin
      DialogThread.ProgressBarPosition(i);
      inc(i);
    end
    else i:=0;
  end;
end;

end.
lg,
jus

jaenicke 1. Mai 2017 00:37

AW: Form in neuem Thread laufen lassen
 
Ich habe nun den Quelltext veröffentlicht, er steht unter der MPL 2.0 zur Verfügung:
https://github.com/jaenicke/MTCL
Der Quelltext darf damit auch explizit für kommerzielle Projekte, egal ob open oder closed source, verwendet werden. Die wichtigste Bedingung ist lediglich, dass eure Änderungen am Quelltext auch wieder zur Verfügung gestellt werden müssen.

Ihr seid alle eingeladen euch an dem Projekt zu beteiligen. Push Requests werde ich möglichst schnell bearbeiten.

Was ich prinzipiell noch plane sobald ich privat die Zeit finde:
  • Dynamische Erzeugung der Controls als Alternative zur Nutzung von Ressourcen
  • Zumindest ein paar Basisproperties wie Position und Größe
  • Und im Anschluss neue Controltypen, insbesondere progressbar usw.

Delphi-Laie 2. Mai 2017 14:39

AW: Form in neuem Thread laufen lassen
 
Hallo Sebastian, vielen Dank für die Veröffentlichung Deines Projektes! Anscheinend konntst Du in Deinem Unternehmen "gewissen Genehmigungen" einholen.

Der einzige Wermuthstropfen ist für mich, daß es eine ziemlich hohe Delphiversion erfordert. Auch nach "Unitbereinigung" war Turbo-Delphi außerstande, es zu compilieren. Es erfordert wohl als Minimum irgendein Delphi der XE-Reihe, nicht wahr? Ich fand dazu keine explizite Aussage.

Aviator 2. Mai 2017 14:43

AW: Form in neuem Thread laufen lassen
 
Zitat:

Zitat von Delphi-Laie (Beitrag 1369843)
Hallo Sebastian, vielen Dank für die Veröffentlichung Deines Projektes! Anscheinend konntst Du in Deinem Unternehmen "gewissen Genehmigungen" einholen.

Der einzige Wermuthstropfen ist für mich, daß es eine ziemlich hohe Delphiversion erfordert. Auch nach "Unitbereinigung" war Turbo-Delphi außerstande, es zu compilieren. Es erfordert wohl als Minimum irgendein Delphi der XE-Reihe, nicht wahr? Ich fand dazu keine explizite Aussage.

Ich habe den SourceCode nur kurz überflogen und mir auch nur das angeschaut, was er hier im Forum gepostet hat. Mir sind dabei Generics ins Auge gesprungen. Die gab es soweit ich weiß erst ab Delphi 2009 oder Delphi 2010. Ohne die Generics könntest du es zwar auch machen indem du die einfach auflöst, aber dann müsstest du jede Komponente selbst handlen bzw. eine sehr weit übergeordnete Basisklasse (TComponent oder so) verwenden.

Aber wie gesagt ... nur kurz überflogen. Wie viel Aufwand das wäre kann ich so nicht sagen.

jaenicke 2. Mai 2017 15:11

AW: Form in neuem Thread laufen lassen
 
Es sollte mit der kostenlosen 10.2 Starter funktionieren.

Generics gehen ab Delphi 2009, aber ob die Unitnamen da schon alle so waren, weiß ich nicht.

Ohne Generics geht es leider bei weitem nicht so elegant. Es sollte da aber reichen die generischen Dictionaries und den generischen Getter zu ersetzen. Ich bin gerade unterwegs, deshalb kann ich grad schlecht schauen.

Delphi-Laie 2. Mai 2017 15:31

AW: Form in neuem Thread laufen lassen
 
Danke Euch beiden!

Nein, Sebastian, wegen meiner fühle Dich bitte nicht genötigt, Deine kostbare Zeit dafür zu ver(sch)wenden, Generics womöglich aufzulösen.

Dann bleibt mir eben nur die Verwendung ab Delphi mit Generics oder Verzicht, wenn die Generics eben so elegant sind.

jus 3. Mai 2017 08:46

AW: Form in neuem Thread laufen lassen
 
Zitat:

Zitat von jaenicke (Beitrag 1369555)
Ich habe nun den Quelltext veröffentlicht, er steht unter der MPL 2.0 zur Verfügung:
https://github.com/jaenicke/MTCL
Der Quelltext darf damit auch explizit für kommerzielle Projekte, egal ob open oder closed source, verwendet werden. Die wichtigste Bedingung ist lediglich, dass eure Änderungen am Quelltext auch wieder zur Verfügung gestellt werden müssen.

Ihr seid alle eingeladen euch an dem Projekt zu beteiligen. Push Requests werde ich möglichst schnell bearbeiten.

Was ich prinzipiell noch plane sobald ich privat die Zeit finde:
  • Dynamische Erzeugung der Controls als Alternative zur Nutzung von Ressourcen
  • Zumindest ein paar Basisproperties wie Position und Größe
  • Und im Anschluss neue Controltypen, insbesondere progressbar usw.

@jaenicke: Danke! :thumb:

lg,
jus

jaenicke 15. Jun 2017 05:40

AW: Form in neuem Thread laufen lassen
 
Hat sich schon jemand das Projekt genauer angeschaut? Die dynamische Erzeugung von Controls ist nun implementiert, genauso wie die Positionierung der Controls zur Laufzeit.
Die dynamische Erzeugung des Fensters an sich steht noch aus, genauso wie Properties wie Font usw. und dann natürlich noch ein paar weitere Controls.

Ich würde mich freuen, wenn sich auch jemand anderes beteiligen würde. ;-)

jaenicke 17. Jun 2017 11:36

AW: Form in neuem Thread laufen lassen
 
Ich habe mal noch eine rudimentäre Progressbar hinzugefügt. :wink:

jus 19. Jun 2017 16:53

AW: Form in neuem Thread laufen lassen
 
Zitat:

Zitat von jaenicke (Beitrag 1374751)
Ich habe mal noch eine rudimentäre Progressbar hinzugefügt. :wink:

Cool, ich muss werde mich mal in den Code reinlesen. Das Problem bei mir aktuell ist halt, dass ich noch Delphi 2007 verwende und somit den Code nicht direkt kompilieren kann. Erschwerend kommt noch hinzu, dass ich keine Ahnung von Generics habe. Gibt es eigentlich ein gutes Tutorial wie Generics funktionieren?

lg,
jus

jaenicke 19. Jun 2017 22:03

AW: Form in neuem Thread laufen lassen
 
Ich habe gerade mal geschaut unter welchen Versionen das ganze eigentlich läuft...
Für Delphi 7 bis 2007 geht es nun, wenn auch nicht wirklich schön. Aber ohne Casts geht es da eben nicht. Und mehr werde ich diesbezüglich auch nicht machen.

Ich habe aber festgestellt, dass es auch mit Delphi 2009 und höher nicht geht, weil die Generics so ihre Tücken hatten. Bis XE6 geht es auf jeden Fall nicht, irgendwann danach kam der Fix. (custom constructor bei type constraint auf eine bestimmte Basisklasse)
Mal schauen...

jaenicke 19. Jun 2017 23:01

AW: Form in neuem Thread laufen lassen
 
Es funktioniert nun mit allen Versionen ab Delphi 7, allerdings musste ich für Delphi 2009 die Benutzung von Generics deaktivieren, da ich dafür keine Zeit investieren wollte. Sprich Generics kommen erst ab Delphi 2010 zum Einsatz. Und auch da waren noch Tricks nötig.

Fazit:
Wer Generics wirklich gut nutzen möchte, sollte sich schon überlegen eine aktuelle Delphiversion zu nutzen. Selbst bei einem so simplen Beispiel stößt man ohne Tricks noch selbst bei XE6 an Grenzen...

jus 20. Jun 2017 22:13

AW: Form in neuem Thread laufen lassen
 
Zitat:

Zitat von jaenicke (Beitrag 1374927)
Es funktioniert nun mit allen Versionen ab Delphi 7, allerdings musste ich für Delphi 2009 die Benutzung von Generics deaktivieren, da ich dafür keine Zeit investieren wollte. Sprich Generics kommen erst ab Delphi 2010 zum Einsatz. Und auch da waren noch Tricks nötig.

Fazit:
Wer Generics wirklich gut nutzen möchte, sollte sich schon überlegen eine aktuelle Delphiversion zu nutzen. Selbst bei einem so simplen Beispiel stößt man ohne Tricks noch selbst bei XE6 an Grenzen...

@jaenicke: Wow, läßt nun auch in Delphi 2007 kompilieren, habe es gerade ausprobiert. Vielen vielen Dank! :-D

lg,
jus

jaenicke 20. Jun 2017 22:20

AW: Form in neuem Thread laufen lassen
 
Gerne ;-)
Im Moment habe ich z.B. das Problem, dass bei dynamischer Erzeugung die Komponenten erst sichtbar werden, wenn ich mit der Maus drüber gehe oder z.B. der Fortschritt der Progressbar geändert wird.
Wenn da jemand eine Idee hätte... ;-)

Purri 26. Jul 2017 14:52

AW: Form in neuem Thread laufen lassen
 
Hallo zusammen,

ich bin auf euer wunderbares Projekt (ein dickes DANKE von mir :-D) gestoßen, weil ich eine Möglichkeit suche eine Aktivitätsanzeige einzublenden, auch wenn im Hauptthread Stillstand herrscht. Ich habe hier zum Teil größere Datenbankoperationen, die ich leider nicht in eigene Threads auslagern kann.

Nun schaue ich mir grade die Demo an und bin dabei auf folgendes gestoßen:

- Unter XE5 kompiliert bei mir keine Datei ( Konnte ich lösen, indem ich bei den Uses "Winapi." vor "Windows" und "Messages" geschrieben habe. Meiner Meinung nach sollte es in XE5 aber auch ohne "Winapi" funktionieren, kann also mein Fehler sein.

- Ich verstehe die Kompilerbedingungen so, das "Delphi2010up" auch von XE5 ausgelöst werden sollte. Das ist, zumindest bei mir, nicht der Fall.

Grüße
Jan

jaenicke 26. Jul 2017 15:53

AW: Form in neuem Thread laufen lassen
 
Zitat:

Zitat von Purri (Beitrag 1377521)
- Unter XE5 kompiliert bei mir keine Datei ( Konnte ich lösen, indem ich bei den Uses "Winapi." vor "Windows" und "Messages" geschrieben habe. Meiner Meinung nach sollte es in XE5 aber auch ohne "Winapi" funktionieren, kann also mein Fehler sein.

Dann fehlt in deinen Projektoptionen der Namespace Winapi. Ich schaue mal, dass ich das per IFDEF löse.

Zitat:

Zitat von Purri (Beitrag 1377521)
- Ich verstehe die Kompilerbedingungen so, das "Delphi2010up" auch von XE5 ausgelöst werden sollte. Das ist, zumindest bei mir, nicht der Fall

Teste ich, muss dafür aber erst eine VM mit XE5 einrichten.

jaenicke 26. Jul 2017 21:09

AW: Form in neuem Thread laufen lassen
 
Ich habe beides bearbeitet. Wenn du neu auscheckst, sollte das passen.

Purri 27. Jul 2017 07:15

AW: Form in neuem Thread laufen lassen
 
Klappt wunderbar. Danke :-D

Purri 27. Jul 2017 13:58

AW: Form in neuem Thread laufen lassen
 
Nochmal ich :?

Eigentlich sollte n der Thread und sein Fenster doch weiterarbeiten, wenn der Hauptthread steht, oder?
Ich habe in der Demo testweise auf dem Hautpformular einen Button mit einem
Delphi-Quellcode:
Sleep(5000);
eingebaut. Wenn ich dies ausführe, während der Thread läuft, bleiben Thread und Threadfenster stehen. Interessanterweise aber nicht sofort: Die "j-Schleife" läuft immer noch zu Ende durch. :wiejetzt:

Kann mir einer von euch erklären, was hier passiert:?:

Edit: Ein Sleep im Hauptthread hält natürlich alles an, aber warum läuft die "j-Schleife" dann weiter?

jaenicke 27. Jul 2017 17:01

AW: Form in neuem Thread laufen lassen
 
Weil die innere Schleife die Fortschrittsanzeige nicht aktualisiert und deshalb keine Messages braucht.

So ist das auch nicht gedacht. Gedacht ist das so, dass du einen eigenen Thread hast, der die Verarbeitung durchführt und die GUI ansteuert. Innerhalb der GUI-Events sollte nichts passieren außer den Aufruf an den Verarbeitungsthread weiterzugeben. Dieser separate Thread kann dann auch problemlos Sleep aufrufen.

Hintergrund ist, dass auch die Messages für die einzelnen Fenster in der Main-Messageloop ankommen und diese so blockiert, wenn eine Messagebehandlung (wie für den Knopfdruck) länger dauert. Vielleicht lässt sich das auch noch sauberer trennen. Freiwillige vor. ;-)


Alle Zeitangaben in WEZ +1. Es ist jetzt 11:57 Uhr.
Seite 2 von 2     12   

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