Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Delphi Vermeiden von Application.Processmessages (https://www.delphipraxis.net/185172-vermeiden-von-application-processmessages.html)

Mavarik 20. Mai 2015 10:02

Vermeiden von Application.Processmessages
 
Zitat:

Zitat von Der schöne Günther (Beitrag 1302257)
Delphi-Quellcode:
OnActivate
-Event

Kommt jedes mal wenn die Form/App den Focus erhält... (Windows)
Create nur 1x!

Doch nochmal zum Thread Thema

Beispiel alt:

Delphi-Quellcode:
procedure TMainForm.FormCreate(Sender: TObject);
begin
  LeftPanel.Width := 100;
  RightPanel.Width := 100;
  // Center Panel is align Client... Aber wie groß jetzt
  Application.Processmessages;
  Width_für_neue_Berechnung := CenterPanel.Width;
  Berechne_Element_auf_CenterPanel(Width_für_neue_Berechnung);
  ...
end;
Beispiel neu:

Delphi-Quellcode:
procedure TMainForm.FormCreate(Sender: TObject);
begin
  LeftPanel.Width := 100;
  RightPanel.Width := 100;
  TThread.Queue(NIL,Procedure ()
                      begin
                        Width_für_neue_Berechnung := CenterPanel.Width;
                        Berechne_Element_auf_CenterPanel(Width_für_neue_Berechnung);
                      end);

  // In der Hoffnung hier den Wert nicht auch zu brauchen...
end;
Mavarik

Der schöne Günther 20. Mai 2015 10:12

AW: Vernichten von Application.Processmessages
 
Zitat:

Zitat von Mavarik (Beitrag 1302261)
Kommt jedes mal wenn die Form/App den Focus erhält... (Windows)
Create nur 1x!

Ja. Zugegeben, man muss man sich einmal merken ob das OnActivate nun schon mal stattgefunden hat oder nicht:

Delphi-Quellcode:
type
   TBaseForm = class(TForm)
      procedure FormActivate(Sender: TObject);
      private var
         firstActivateHappened: Boolean;
      public
         procedure initGUI(); virtual;
   end;

procedure TBaseForm.initGUI();
begin
   // Empty
end;

procedure TBaseForm.FormActivate(Sender: TObject);
begin
   if (not firstActivateHappened) then begin
      initGUI();
      firstActivateHappened := True;
   end;
   inherited;
end;
Das sind zwar zwei Zeilen mehr als es im OnCreate zu machen, aber eine Boolean-Variable ist im Vergleich zu einem
Delphi-Quellcode:
TThread.Queue(..)
oder
Delphi-Quellcode:
Application.ProcessMessages()
so herrlich unspektakulär ;-)

Du hättest nun einfach
Delphi-Quellcode:
procedure TMainForm.initGUI();
begin
   inherited;   
   Berechne_Element_auf_CenterPanel(CenterPanel.Width);
end;
Genau für Dinge wie "Wie groß ist das Element nun?" nehme ich immer "meine"
Delphi-Quellcode:
OnActivate
-Lösung und war damit eigentlich immer glücklich.

baumina 20. Mai 2015 10:14

AW: Vernichten von Application.Processmessages
 
Ich hab sowas in OnShow ebenfalls mit einer Variable FirstShow.

Der schöne Günther 20. Mai 2015 10:17

AW: Vernichten von Application.Processmessages
 
Ja, das wäre ja genau das gleiche. :-) Ich meine, ich hatte irgendeinen Grund,
Delphi-Quellcode:
OnActivate
statt
Delphi-Quellcode:
OnShow
zu nehmen. Wenn ich nicht falsch liege, kommt erst
Delphi-Quellcode:
OnShow
, dann
Delphi-Quellcode:
OnActivate
.

Sir Rufo 20. Mai 2015 10:23

AW: Vernichten von Application.Processmessages
 
Hier mal ein Best Practice und DontDo Beispiel
Delphi-Quellcode:
unit Form.Main;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Objects,
  FMX.Controls.Presentation, FMX.StdCtrls;

type
  TForm1 = class( TForm )
    ToolBar1: TToolBar;
    Text1: TText;
    Label1: TLabel;
    procedure FormCreate( Sender: TObject );
  private
    procedure MeasureTextControl( AText: TText );
    procedure QueueMeasureTextControl( AText: TText );
    procedure DontDoMeasureTextControl( AText: TText );
  public

  end;

var
  Form1: TForm1;

implementation

{$R *.fmx}

{ TForm1 }

procedure TForm1.FormCreate( Sender: TObject );
begin
  Text1.Align := TAlignLayout.Client;

  // funktioniert
  // MeasureTextControl( Text1 );

  // funktioniert - Best Practice
  QueueMeasureTextControl( Text1 );

  // Fehlerhafte Darstellung
  // DontDoMeasureTextControl( Text1 );
end;

procedure TForm1.DontDoMeasureTextControl( AText: TText );
begin
  Application.ProcessMessages;
  MeasureTextControl( AText );
end;

procedure TForm1.MeasureTextControl( AText: TText );
begin
  Label1.Text := AText.Width.ToString;
end;

procedure TForm1.QueueMeasureTextControl( AText: TText );
begin
  TThread.Queue( nil,
    procedure
    begin
      MeasureTextControl( AText );
    end );
end;

end.

himitsu 20. Mai 2015 10:48

AW: Vernichten von Application.Processmessages
 
TThread.Queue kannst du dir an der Stelle sparen, da es sofort ausgeführt wird.
(zumindestens in Windows, aber vermutlich auch im NextGen usw.)

http://www.delphipraxis.net/179193-t...der-queue.html

Mavarik 20. Mai 2015 11:52

AW: Vernichten von Application.Processmessages
 
Zitat:

Zitat von himitsu (Beitrag 1302273)
TThread.Queue kannst du dir an der Stelle sparen, da es sofort ausgeführt wird.
(zumindestens in Windows, aber vermutlich auch im NextGen usw.)

http://www.delphipraxis.net/179193-t...der-queue.html

:stupid: Das kommt davon, wenn man ungetesten code postet...

Hatte ich inzwischen schon geändert... in einen OnIdle Handler...

Sir Rufo 20. Mai 2015 12:01

AW: Vernichten von Application.Processmessages
 
Ja, ja ... :stupid:

Dann ebend so ... menno :mrgreen:

Delphi-Quellcode:
procedure TForm1.QueueMeasureTextControl( AText: TText );
begin
  TThread.ExecLater<TText>( MeasureTextControl, AText );
end;
Gut, dafür braucht man einen ThreadHelper
Delphi-Quellcode:
unit ThreadHelper;

interface

uses
  System.Classes,
  System.SysUtils;

type
  TThreadHelper = class helper for TThread
    class procedure ExecLater( AProc: TProc ); overload;
    class procedure ExecLater<T>( AProc: TProc<T>; AArg: T ); overload;
    class procedure ExecLater<T1, T2>( AProc: TProc<T1, T2>; AArg1: T1; AArg2: T2 ); overload;
    class procedure ExecLater<T1, T2, T3>( AProc: TProc<T1, T2, T3>; AArg1: T1; AArg2: T2; AArg3: T3 ); overload;
    class procedure ExecLater<T1, T2, T3, T4>( AProc: TProc<T1, T2, T3, T4>; AArg1: T1; AArg2: T2; AArg3: T3; AArg4: T4 ); overload;
  end;

implementation

{ TThreadHelper }

class procedure TThreadHelper.ExecLater( AProc: TProc );
begin
  TThread.CreateAnonymousThread(
    procedure
    begin
      TThread.Current.Synchronize(
        procedure
        begin
          AProc( );
        end );
    end ).Start( );
end;

class procedure TThreadHelper.ExecLater<T1, T2, T3, T4>( AProc: TProc<T1, T2, T3, T4>; AArg1: T1; AArg2: T2; AArg3: T3; AArg4: T4 );
begin
  TThread.CreateAnonymousThread(
    procedure
    begin
      TThread.Current.Synchronize(
        procedure
        begin
          AProc( AArg1, AArg2, AArg3, AArg4 );
        end );
    end ).Start( );
end;

class procedure TThreadHelper.ExecLater<T1, T2, T3>( AProc: TProc<T1, T2, T3>; AArg1: T1; AArg2: T2; AArg3: T3 );
begin
  TThread.CreateAnonymousThread(
    procedure
    begin
      TThread.Current.Synchronize(
        procedure
        begin
          AProc( AArg1, AArg2, AArg3 );
        end );
    end ).Start( );
end;

class procedure TThreadHelper.ExecLater<T1, T2>( AProc: TProc<T1, T2>; AArg1: T1; AArg2: T2 );
begin
  TThread.CreateAnonymousThread(
    procedure
    begin
      TThread.Current.Synchronize(
        procedure
        begin
          AProc( AArg1, AArg2 );
        end );
    end ).Start( );
end;

class procedure TThreadHelper.ExecLater<T>( AProc: TProc<T>; AArg: T );
begin
  TThread.CreateAnonymousThread(
    procedure
    begin
      TThread.Current.Synchronize(
        procedure
        begin
          AProc( AArg );
        end );
    end ).Start( );
end;

end.

Daniel 20. Mai 2015 12:12

AW: Vermeiden von Application.Processmessages
 
Ich habe mir erlaubt, den Themen-Titel anzupassen.
Vermutlich geht es eher um "vermeiden" als "vernichten".

Thomas_K 20. Mai 2015 13:19

AW: Vernichten von Application.Processmessages
 
Zitat:

Zitat von Der schöne Günther (Beitrag 1302263)

Ja. Zugegeben, man muss man sich einmal merken ob das OnActivate nun schon mal stattgefunden hat oder nicht:

Delphi-Quellcode:
type
   TBaseForm = class(TForm)
      procedure FormActivate(Sender: TObject);
      private var
         firstActivateHappened: Boolean;
      public
         procedure initGUI(); virtual;
   end;

procedure TBaseForm.initGUI();
begin
   // Empty
end;

procedure TBaseForm.FormActivate(Sender: TObject);
begin
   if (not firstActivateHappened) then begin
      initGUI();
      firstActivateHappened := True;
   end;
   inherited;
end;

Die Hilfsvariablensteuerung kann man sich sparen, wenn sich die Ereignis- Routine selbst vom Objekt/Instanz abkoppelt.

Delphi-Quellcode:
type
  TBaseForm = class(TForm)
    procedure FormActivate(Sender: TObject);
  public
    procedure initGUI(); virtual;
  end;

procedure TBaseForm.initGUI();
begin
   // Empty
end;

procedure TBaseForm.FormActivate(Sender: TObject);
begin
   OnActivate = nil;
   initGUI();
   firstActivateHappened := True;
   inherited;
end;
Die selbe Funktionalität wie oben, nur mit weniger Code.


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