Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Control zuweisen (https://www.delphipraxis.net/206796-control-zuweisen.html)

MicMic 30. Jan 2021 13:41

Delphi-Version: 10.3 Rio

Control zuweisen
 
Hallo,
ich mache das recht oft aber bin mir eigentlich nicht sicher, ob das Nachteile hat.
Als Beispiel für eine ListBox in OnDrawItem:
Delphi-Quellcode:
Procedure ... DrawItem(Control: TWinControl; Index: Integer;...
Var L : TListBox;
Begin
  L := TListBox(Control);
  If L.Columns = 0 Then...
End;
Also ich mache sowas gerne, damit der weitere Verlauf im Code abgekürzt ist. Nicht nur bei einer ListBox. Sonst müsste ich in diesem Fall immer "TListBox(Control)." angeben. So ein DrawItem-Ereignis wird ja oft aufgerufen und die zuweisen erfolgt dann natürlich auch immer sehr oft. Aber denke das ist ok so. Man könnte z.B. noch die Zeile "Var L : TListBox;" Global setzen. Wenn ich darauf achte, dass diese Variable "L" nicht woanders genutzt wird, würde dies dann für "OnDrawItem" ein Vorteil sein? Oder ist das ganz egal? Zuweisen muss ich ja sowieso aber das "Var L : TListBox;" wäre dann woanders. Jedenfalls bringt es mir viel im Code (für die Übersicht):
Delphi-Quellcode:
  If Index = Ceil(TListBox(Control).ClientHeight / TListBox(Control).ItemHeight)-1+TListBox(Control).TopIndex Then // langer Code
  If Index = Ceil(L.ClientHeight / L.ItemHeight)-1+L.TopIndex Then // kurzer Code

himitsu 30. Jan 2021 13:59

AW: Control zuweisen
 
Für den Compiler ist es komplett egal und auch vom erzeugten Code ergibt es praktisch keinen Unterschied,

also ob du auf die eine Variable mit einem Casts zugreifst,
oder ob das nur einmal in eine andere Variable kopiert und dann Jene benutzt.

Einen Unterschied gibt es bei harten Cast
Delphi-Quellcode:
TListBox(Control)
gegenüber einem weichen Cast
Delphi-Quellcode:
(Control as TListBox)
.
Falls mehrmal genutzt und der Weiche, mit "Prüfung" ob der Typ in der Variable wirklich passt, nötig ist, dann braucht man nur beim ersten Zugriff einen Weichen und es kann später Hart sein, da es sich ja nicht ändern wird.


PS:
Delphi-Quellcode:
Procedure ... DrawItem(Control: TWinControl; Index: Integer;...
Var L : TListBox absolute Control;
Begin
  If L.Columns = 0 Then...
End;
L ist ein "Alias" für den Speicherplatz von Control (kann/darf auch ein anderer Typ sein, aber nur gleichgroß oder kleiner, wie der originale Typ)

Dein L ist eine Kopie (des Objektzeiger/Pointer) und mit absolute ist es die "gleiche" Variable.


oder ... aber das will niemand machen
Delphi-Quellcode:
begin
  with TListBox(Control) do
    if Columns = 0 then...
end;

MicMic 30. Jan 2021 14:11

AW: Control zuweisen
 
Danke. "L" war nur ein Beispiel. Nutze es nicht nur bei einer ListBox. Hier in diesem Fall nehme ich "LB" als Variable.
In vielen Code-Bereichen wird der Code dann einfach etwas übersichtlicher
Wenn es Delphi wurscht ist, lasse ich die "Var-Zeile", da wo es sie ist.
Vielen Dank

BigAl 31. Jan 2021 05:42

AW: Control zuweisen
 
Zitat:

Zitat von himitsu (Beitrag 1481808)
...
oder ... aber das will niemand machen
Delphi-Quellcode:
begin
  while TListBox(Control) do
    if Columns = 0 then...
end;

Du meintest sicher:
Delphi-Quellcode:
begin
  with TListBox(Control) do
  begin
    if Columns = 0 then
    ...
  end;
end;
oder?

Habe ich mir aber abgewöhnt, da man immer aufpassen muss nicht die falsche Variable / Funktion zu erwischen. Lieber etwas mehr tippen. Es ist dann auch einfacher Code-Fragmente zu kopieren...

himitsu 31. Jan 2021 15:41

AW: Control zuweisen
 
ups, ja WITH. :lol:


Ich hatte z.B. in etwa folgenden Code in einer TForm gesehn:
Als Kommentare das, was der Entwickler sich dabei dachte, bzw. was der Compiler neuerdings daraus machte.
Delphi-Quellcode:
var Rect: TRect;

with Rect do
  {Self.}Width := {Rect.}Right - {Rect.}Left;
Das funktionierte super, so lange sich nichts veränderte und TRect so aussah
Delphi-Quellcode:
  TRect = record
    Left, Top, Right, Bottom: Integer;
  end;

  //bzw.
  TRect = record
  case Integer of
    0: (Left, Top, Right, Bottom: Integer);
    1: (TopLeft, BottomRight: TPoint);
  end;
Und dann wunderte man sich, dass der Code plötzlich nicht mehr funktionierte und die Form ihre Größe nicht mehr anpasste, denn
Delphi-Quellcode:
var Rect: TRect;

with Rect do
  {Rect.}Width := {Rect.}Right - {Rect.}Left;
Delphi-Quellcode:
  TRect = record
  ...
  public
    ...
    property Width: Integer read GetWidth write SetWidth;
    ...
  case Integer of
    0: (Left, Top, Right, Bottom: FixedInt);
    1: (TopLeft, BottomRight: TPoint);
  end;
Auch TForm und andere Komponenten/Klassen bekommen irgendwann mal neue Funktionen, an die niemand damals dachte.

Zitat:

Delphi-Quellcode:
  TRect = record
  private
    function GetWidth: Integer;
    procedure SetWidth(const Value: Integer);
    function GetHeight: Integer;
    procedure SetHeight(const Value: Integer);
    function GetSize: TSize;
    procedure SetSize(const Value: TSize);
    function GetLocation: TPoint;
  public
    constructor Create(const Origin: TPoint); overload;                             // empty rect at given origin
    constructor Create(const Origin: TPoint; Width, Height: Integer); overload;     // at TPoint of origin with width and height
    constructor Create(const Left, Top, Right, Bottom: Integer); overload;          // at Left, Top, Right, and Bottom
    constructor Create(const P1, P2: TPoint; Normalize: Boolean = False); overload; // with corners specified by p1 and p2
    constructor Create(const R: TRect; Normalize: Boolean = False); overload;

    // operator overloads
    class operator Equal(const Lhs, Rhs: TRect): Boolean;
    class operator NotEqual(const Lhs, Rhs: TRect): Boolean;

    // union of two rectangles
    class operator Add(const Lhs, Rhs: TRect): TRect;

    // intersection of two rectangles
    class operator Multiply(const Lhs, Rhs: TRect): TRect;

    class function Empty: TRect; inline; static;

    //utility methods
    //makes sure TopLeft is above and to the left of BottomRight
    procedure NormalizeRect;

    //returns true if left = right or top = bottom
    function IsEmpty: Boolean;

    //returns true if the point is inside the rect
    function Contains(const Pt: TPoint): Boolean; overload;

    // returns true if the rect encloses R completely
    function Contains(const R: TRect): Boolean; overload;

    // returns true if any part of the rect covers R
    function IntersectsWith(const R: TRect): Boolean;

    // computes an intersection of R1 and R2
    class function Intersect(const R1: TRect; const R2: TRect): TRect; overload; static;

    // replaces current rectangle with its intersection with R
    procedure Intersect(const R: TRect); overload;

    // computes a union of R1 and R2
    class function Union(const R1: TRect; const R2: TRect): TRect; overload; static;

    // replaces current rectangle with its union with R
    procedure Union(const R: TRect); overload;

    // creates a minimal rectangle that contains all points from array Points
    class function Union(const Points: Array of TPoint): TRect; overload; static;

    // offsets the rectangle origin relative to current position
    procedure Offset(const DX, DY: Integer); overload;
    procedure Offset(const Point: TPoint); overload;

    // sets new origin
    procedure SetLocation(const X, Y: Integer); overload;
    procedure SetLocation(const Point: TPoint); overload;

    // inflate by DX and DY
    procedure Inflate(const DX, DY: Integer); overload;

    // inflate in all directions
    procedure Inflate(const DL, DT, DR, DB: Integer); overload;

    //returns the center point of the rectangle;
    function CenterPoint: TPoint;

    function SplitRect(SplitType: TSplitRectType; Size: Integer): TRect; overload;
    function SplitRect(SplitType: TSplitRectType; Percent: Double): TRect; overload;

    // changing the width is always relative to Left;
    property Width: Integer read GetWidth write SetWidth;
    // changing the Height is always relative to Top
    property Height: Integer read GetHeight write SetHeight;

    property Size: TSize read GetSize write SetSize;

    property Location: TPoint read GetLocation write SetLocation;

  case Integer of
    0: (Left, Top, Right, Bottom: FixedInt);
    1: (TopLeft, BottomRight: TPoint);
  end;


BigAl 31. Jan 2021 16:02

AW: Control zuweisen
 
Genau das meinte ich. "with" ist immer gefährlich wenn man nicht genau weiß was man macht bzw. wo der Code noch zum Einsatz kommt.

Ich hatte mich früher in C++ aufgeregt, dass es da das "with" in der Form nicht gibt. Mittlerweile bin ich froh drum. Man kann dort aber in ähnliche Probleme mit den "namespaces" laufen...

Aber an besten ausschreiben. Und wenn der Bezeichner in den Parametern doch unmöglich lange ist, dann kann man ja immer noch den Weg über "var x: ... absolute ..." gehen...

freimatz 2. Feb 2021 08:56

AW: Control zuweisen
 
Zitat:

Zitat von MicMic (Beitrag 1481807)
Hallo,
ich mache das recht oft aber bin mir eigentlich nicht sicher, ob das Nachteile hat.
Als Beispiel für eine ListBox in OnDrawItem:
Delphi-Quellcode:
Procedure ... DrawItem(Control: TWinControl; Index: Integer;...
Var L : TListBox;
Begin
  L := TListBox(Control);
  If L.Columns = 0 Then...
End;

Auch nach längerem Überlegen fällt mir fast kein Nachteil ein. Es könnte Fälle geben wo jemand motzt weil eine eine MNethod wegen den zwei Zeilen zu lange ist.
Auf jeden Fall: machs:!:
Die Vorteile vor allem wegen der Übersichtlichkeit überwiegen deutlich. :thumb:

mkinzler 2. Feb 2021 09:03

AW: Control zuweisen
 
[QUOTE=freimatz;1481997]
Zitat:

Zitat von MicMic (Beitrag 1481807)
Hallo,
ich mache das recht oft aber bin mir eigentlich nicht sicher, ob das Nachteile hat.

Nein. Ich könnte in diesem Fall auch einen "soften" Cast verwenden, dann ist es sicher sicher.

himitsu 2. Feb 2021 09:26

AW: Control zuweisen
 
Ja, das mit Soft und Hart hatte ich schon erwähnt.

Der Gedanke des Grundproblems war aber nicht die Art des Castes (auch wenn da deine Aussage stimmt),
sondern es ging garum den "mehrfachen" Cast vorher in einer Variable zwischenzuspeichern und dann überall die Variable zu verwenden.
* Hier hat die Variable eigentlich mehr Vorteile, gegenüber den 4-8 Byte mehr für die neue Varialbe

* Und ja, wenn man das noch für den soften Cast betrachtet, dann ist "einmal" der Cast, gegenüber Mehrmals noch vorteilhafter.


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