Position et Dimensions des TControls

Position et dimensions des Controls

Constraints

Sources :

TControl.Constraints peut être utiliser pour définir les dimensions max et min d'un Control.

published
  property OnChange: TNotifyEvent;  // [rw] Event handler for a change in the constraints.
  property MaxHeight: TConstraintSize; // [rw] The maximum height.
  property MaxWidth: TConstraintSize; // [rw]  The maximum width.
  property MinHeight: TConstraintSize; // [rw]  The minimum height.
  property MinWidth: TConstraintSize; // [rw] The minimum width.
end;

Un exemple d'utilisation est donné ci-dessous dans la section AdjustClientRect

GetLogicalClientRect

Source : https://lazarus-ccr.sourceforge.io/docs/lcl/controls/tcontrol.getlogicalclientrect.html

La fonction TControl.GetLogicalClientRect a pour rôle d'obtenir les dimensions de la zone cliente d'un contrôle en tenant compte des coordonnées logiques. Cela signifie qu'elle retourne la zone disponible pour les composants enfants, excluant les bordures et autres éléments non-clients, en tenant compte des transformations ou des échelles logiques appliquées au contrôle.

Rôle de GetLogicalClientRect :

  • Récupération des dimensions réelles : La méthode renvoie un rectangle (TRect) représentant les dimensions de la zone cliente en coordonnées logiques.
  • Gestion des transformations : Elle prend en compte les transformations éventuelles, telles que l'échelle, les rotations ou les autres modifications logiques appliquées au contrôle.

AdjustClientRect

Source : https://lazarus-ccr.sourceforge.io/docs/lcl/controls/twincontrol.adjustclientrect.html

TWinControl.AdjustClientRect est une méthode appelée pour ajuster la zone cliente d'un contrôle fenêtré, c'est-à-dire l'espace disponible pour ses composants enfants. Elle permet de :

  • Redéfinir la zone cliente en tenant compte des bordures, marges, ou autres éléments spécifiques au contrôle.
  • Personnaliser la zone disponible pour les composants enfants en fonction des besoins du contrôle.

Les classes descendants peuvent redéfinir cette méthode pour modifier Rect, représentant la zone cliente, afin de gérer précisément l'espace intérieur du contrôle.

Exemple d'utilisation : Utiliser les Constraints pour definir une largeur et hauteur minimale

type
  TMyControl = class(TWinControl)
  protected
    procedure AdjustClientRect(var Rect: TRect); override; //surcharge de la méthode
  end;
 
procedure TMyControl.AdjustClientRect(var ARect: TRect);
begin
  inherited AdjustClientRect(ARect); // Appeler la méthode héritée pour ajustements de base
  ARect.Height:=max(Constraints.MinHeight,ARect.Height); // Empêche la hauteur d'etre inferieur à la hauteur minimale contenue dans Contraints
  ARect.Width:=max(Constraints.MinWidth,ARect.Width); // Pareil pour la largeur
end;

Comme indiqué dans le code, la méthode AdjustClientRect est appelée fréquemment, donc n'y mettez pas de code coûteux, ou mettez en cache le résultat.

\lcl\include\wincontrol.inc
{------------------------------------------------------------------------------
  TWinControl AdjustClientRect
------------------------------------------------------------------------------}
procedure TWinControl.AdjustClientRect(var ARect: TRect);
begin
  // Can be overriden.
  // It's called often, so don't put expensive code here, or cache the result
end;

TControl.BoundsRect

function TControl.GetBoundsRect: TRect;
begin
  Result.Left := FLeft;
  Result.Top := FTop;
  Result.Right := FLeft+FWidth;
  Result.Bottom := FTop+FHeight;
end;

TControl.ClientToScreen

{------------------------------------------------------------------------------
  function TControl.ClientToScreen(const APoint: TPoint): TPoint;
------------------------------------------------------------------------------}
function TControl.ClientToScreen(const APoint: TPoint): TPoint;
var
  P : TPoint;
begin
  P := ClientOrigin;
  Result.X := APoint.X + P.X;
  Result.Y := APoint.Y + P.Y;
end;
 
function TControl.ClientToScreen(const ARect: TRect): TRect;
var
  P : TPoint;
begin
  P := ClientToScreen(Point(0, 0));
  Result := ARect;
  Result.Offset(P);
end;

Redimensionnement (AutoSize)

Bloquer le redimensionnement

A Tester

En surchargeant la function :function TWinControl.AutoSizeDelayed: boolean; on peut bloquer le redimensionnement.

Je pense qu'il faut aussi surcharger : AutoSizeDelayedReport et AutoSizeDelayedHandle

\lcl\include\wincontrol.inc
{------------------------------------------------------------------------------
  function TWinControl.AutoSizeDelayed: boolean;
------------------------------------------------------------------------------}
function TWinControl.AutoSizeDelayed: boolean;
begin
  Result:=(csDestroyingHandle in ControlState)
          or (inherited AutoSizeDelayed);
end;
 
function TWinControl.AutoSizeDelayedReport: string;
begin
  if csDestroyingHandle in ControlState then
    Result:='csDestroyingHandle'
  else
    Result:=inherited AutoSizeDelayedReport;
end;
 
{------------------------------------------------------------------------------
  TWinControl AutoSizeDelayedHandle
 
  Returns true if AutoSize should be skipped / delayed because of its handle.
  A TWinControl needs a parent handle.
------------------------------------------------------------------------------}
function TWinControl.AutoSizeDelayedHandle: Boolean;
begin
  Result := (Parent = nil) and (ParentWindow = 0);
end;                                  

Capter le changement de Size du Parent

Avec le Handler OnResize du Parent

  • Le code ci-dessous met en place, grace a AddHandlerOnResize, une logique permettant à un contrôle personnalisé de répondre aux événements de redimensionnement de son Parent.
  • Grace a la surcharge de la procédure SetParent, lorsqu'un changement de parent a lieu, il désinscrit l'ancien parent des événements de redimensionnement et inscrit le nouveau parent, garantissant ainsi que OnParentResizeHandler est appelé chaque fois que le parent est redimensionné.
  • Cette fonctionnalité pourrait être utilisée pour ajuster dynamiquement le contrôle enfant en fonction des dimensions de son parent.
  TMyControl = class(TCustomControl)
  private
    procedure OnParentResizeHandler(Sender: TObject);
  protected
    procedure SetParent(NewParent: TWinControl); override;
  public ...
  end;
 
 
procedure TMyControl.OnParentResizeHandler(Sender: TObject);
begin
  Debugln('%s.OnParentResizeHandler PWith[%d]', [Name, Parent.ClientWidth]);
end;
 
procedure TMyControl.SetParent(NewParent: TWinControl);
var
  vOldParent: TWinControl;
begin
  vOldParent := Parent;
  inherited SetParent(NewParent);
  if Parent <> vOldParent then
  begin
    if assigned(vOldParent) then
      vOldParent.RemoveHandlerOnResize(@OnParentResizeHandler);
    if assigned(Parent) then
      Parent.AddHandlerOnResize(@OnParentResizeHandler, False);
  end;
end;        

Avec interception du message WM_SIZE

protected
  procedure WndProc(var TheMessage: TLMessage); override;
...
 
procedure TMyControl.WndProc(var TheMessage: TLMessage);
var
  vWMSize: TWMSize; 
begin
  inherited WndProc(TheMessage);
  if TheMessage.Msg = WM_SIZE then
  begin
    vWMSize := TWMSize(TheMessage);
 
    DebugLn('%s.WndProc : Le parent a été redimensionné, SizeType[%d] H[%d] W[%d]',
      [Name, vWMSize.SizeType, vWMSize.Height, vWMSize.Width]);
    // Le parent a été redimensionné
    // Implémenter ici la logique de redimensionnement du contrôle
  end;
end;
TWMSize.SizeType

le paramétre SizeType peut avoir les valeurs suivantes :

unit Windows (\fpc\3.2.2\source\rtl\win\wininc\defines.inc)
  { WM_SIZE message  }
     SIZE_MAXHIDE = 4;
     SIZE_MAXIMIZED = 2;
     SIZE_MAXSHOW = 3;
     SIZE_MINIMIZED = 1;
     SIZE_RESTORED = 0;

Il peut arriver que les valeurs soit :

  • SizeType = 6 : Force le realignement (voir ci-dessous)
  • SizeType = 128 : JE NE SAIS PAS ???

SizeType = 6

unit Controls (\lcl\include\wincontrol.inc)
procedure TWinControl.SendMoveSizeMessages(SizeChanged, PosChanged: boolean);
begin
   ...
    with SizeMsg do
    begin
      Msg := LM_SIZE;
      SizeType := 6; // force realign
   ...      
      Width := FWidth;
      Height := FHeight;
   ...
    WindowProc(TLMessage(SizeMsg));
  end;                                              
Vous pourriez laisser un commentaire si vous étiez connecté.