Redimensionnement panel avec alignements

Résolu
zwyx Messages postés 146 Date d'inscription jeudi 22 novembre 2007 Statut Membre Dernière intervention 21 mars 2016 - 5 nov. 2009 à 18:19
cs_Delphiprog Messages postés 4297 Date d'inscription samedi 19 janvier 2002 Statut Membre Dernière intervention 9 janvier 2013 - 7 nov. 2009 à 13:37
Bonjour,

Je dispose d'une colonne (un TPanel) remplie de cellules (d'autres TPanel), toutes alignées en alBottom, sauf la première qui l'est en alClient.

Quand ma colonne change de hauteur, seules les deux premières cellules du haut doivent être redimensionnées. Du coup, je modifie la hauteur de la deuxième cellule. Cela force la première cellule à se redimensionner également, puisqu'elle est alignée en alClient.

Jusqu'ici, tout va bien. Mais le souci est que suite à ce redimensionnement, les deuxième et troisième cellules (en partant du haut) échangent leur place.

De plus, sur l'évènement OnResize de ma fiche contenant cette colonne, quand je cherche à récupérée la hauteur de ma première cellule, alignée en alClient, le résultat est manifestement faux.

Voilà, je suis un peu dérouté face à ce comportement imprévisible de Delphi 7. Une fois de plus, je compte sur votre aide.

Bonne soirée.

8 réponses

cs_Delphiprog Messages postés 4297 Date d'inscription samedi 19 janvier 2002 Statut Membre Dernière intervention 9 janvier 2013 32
7 nov. 2009 à 11:32
Je confirme que cette différence de comportement est assez troublante.

@thwilliam : désolé, mais ta solution ne fonctionne pas et mes neurones ont eu bien du mal à comprendre tes explications. A ta décharge, un dessin serait plus facile à comprendre qu'un long discours.

Aussi, je propose une solution bien plus simple.
Puisque la hauteur de PnlB1 est aussi de la moitié de la hauteur de PnlA1, alors il suffit d'inverser les rôles entre PnlB1 et PnlB2.
Pour faire plus clair, ce n'est pas PnlB1 qui devra avoir sa propriété Align à alClient mais PnlB2, et PnlB1 aura sa propriété Align affectée à AlTop.
Ainsi, le code suivant fonctionne aussi bien en étirant les bords de la fiche qu'en faisant un double clic sur la barre de titre :

procedure TForm1.FormResize(Sender: TObject);
begin
  PnlB1.Height := PnlA1.Height div 2;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  // Propriétés paramétrables, bien évidemment,  dans 
  // l'inspecteur d'objet :
  PnlB1.Align := alTop;
  PnlB2.Align := alClient;
end;


@zwyx : félicitations pour ton exposé clair du problème et pour avoir fourni tous les éléments permettant de rechercher une solution rapidement. Si tout le monde était comme toi, le monde serait merveilleux...

Bon, vous allez me dire que la solution c'est bien mais qu'on ne sait toujours pas pourquoi le programme se comporte ainsi. A cela je répondrai que si quelqu'un a du temps à passer pour en connaitre la cause, sa réponse sera la bienvenue.

Bonne continuation.

8000 Lévriers 'galgos' par an sont torturés et massacrés en Espagne
May Delphi be with you

Pensez à cliquer sur Réponse acceptée lorsque la réponse vous convient.
3
JulioDelphi Messages postés 2226 Date d'inscription dimanche 5 octobre 2003 Statut Membre Dernière intervention 18 novembre 2010 14
6 nov. 2009 à 09:27
Hello
Ecoute, je viens de faire l même programme que toi, et tout se passe bien ...
Peux tu nous montrer ton code ? Merci !
0
zwyx Messages postés 146 Date d'inscription jeudi 22 novembre 2007 Statut Membre Dernière intervention 21 mars 2016
6 nov. 2009 à 15:53
Merci pour ton investigation Julio,

Alors effectivement, quand on agrandit la fenêtre en étirant petit à petit ses bords, les panels restent bien en place. Mais lorsque l'on l'agrandit brutalement en double cliquant sur sa barre de titre par exemple, les panels de la colonne font une partie de chaises musicales.

Voici un petit exemple que je viens d'écrire, qui met en évidence mon problème, du moins, sous Delphi 7.

Unit1.pas
unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    GbxA: TGroupBox;
    GbxB: TGroupBox;
    PnlB1: TPanel;
    PnlB2: TPanel;
    PnlB3: TPanel;
    PnlB4: TPanel;
    PnlB5: TPanel;
    PnlA1: TPanel;
    PnlA2: TPanel;
    PnlA3: TPanel;
    PnlA4: TPanel;
    procedure FormResize(Sender: TObject);
  private
    { Déclarations privées }
  public
    { Déclarations publiques }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormResize(Sender: TObject);
begin
  PnlB2.Height :=  PnlA1.Height div 2;
end;

end.

Uni1.dfm
object Form1: TForm1
  Left  = 455
  Top = 259
  Width = 308
  Height = 551
  Caption = 'Form1'
  Color = clBtnFace
  Constraints.MinHeight = 551
  Constraints.MinWidth = 308
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'MS Sans Serif'
  Font.Style = []
  OldCreateOrder = False
  OnResize = FormResize
  PixelsPerInch = 96
  TextHeight = 13
  object GbxA: TGroupBox
    Left = 0
    Top = 0
    Width = 150
    Height = 517
    Align = alLeft
    Caption = 'Colonne A (alLeft)'
    TabOrder = 0
    object PnlA1: TPanel
      Left = 2
      Top = 15
      Width = 146
      Height = 200
      Align = alClient
      Caption = 'A1 (alClient)'
      Color = clScrollBar
      TabOrder = 0
    end
    object PnlA2: TPanel
      Left = 2
      Top = 215
      Width = 146
      Height = 100
      Align = alBottom
      Caption = 'A2 (alBottom)'
      TabOrder = 1
    end
    object PnlA3: TPanel
      Left = 2
      Top = 315
      Width = 146
      Height = 100
      Align = alBottom
      Caption = 'A3 (alBottom)'
      TabOrder = 2
    end
    object PnlA4: TPanel
      Left = 2
      Top = 415
      Width = 146
      Height = 100
      Align = alBottom
      Caption = 'A4 (alBottom)'
      TabOrder = 3
    end
  end
  object GbxB: TGroupBox
    Left = 150
    Top = 0
    Width = 150
    Height = 517
    Align = alClient
    Caption = 'Colonne B (alClient)'
    TabOrder = 1
    object PnlB1: TPanel
      Left = 2
      Top = 15
      Width = 146
      Height = 100
      Align = alClient
      Caption = 'B1 (alClient)'
      Color = clScrollBar
      TabOrder = 0
    end
    object PnlB2: TPanel
      Left = 2
      Top = 115
      Width = 146
      Height = 100
      Align = alBottom
      Caption = 'B2 (alBottom)'
      TabOrder = 1
    end
    object PnlB3: TPanel
      Left = 2
      Top = 215
      Width = 146
      Height = 100
      Align = alBottom
      Caption = 'B3 (alBottom)'
      TabOrder = 2
    end
    object PnlB4: TPanel
      Left = 2
      Top = 315
      Width = 146
      Height = 100
      Align = alBottom
      Caption = 'B4 (alBottom)'
      TabOrder = 3
    end
    object PnlB5: TPanel
      Left = 2
      Top = 415
      Width = 146
      Height = 100
      Align = alBottom
      Caption = 'B5 (alBottom)'
      TabOrder = 4
    end
  end
end
0
JulioDelphi Messages postés 2226 Date d'inscription dimanche 5 octobre 2003 Statut Membre Dernière intervention 18 novembre 2010 14
6 nov. 2009 à 16:14
Je suis bluffé, effectivement la colonne b2 se retrouve sous b4 ...
Et ça, quand on agrandi la fenetre via l'icone de barre de titre (ou dbl click) ...
En ajoutant "PnlB2.Top:= 1;" sous le "PnlB2.Height := PnlA1.Height div 2;" ça marche.
Pourquoi ? Je n'ai pas la réponse par contre ...
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
zwyx Messages postés 146 Date d'inscription jeudi 22 novembre 2007 Statut Membre Dernière intervention 21 mars 2016
6 nov. 2009 à 17:17
C'est déjà bien, même si c'est une bidouille, ça résout mon problème.

Je pense que le problème provient de la moulinette interne de Delphi, quand il positionne les éléments dans un certain ordre, en fonction de leur propriété d'alignement.

Je ne marque pas tout de suite "Réponse accetpée", car j'aimerais avoir des explications supplémentaires sur ce phénomène, mais je n'oublierai pas.

Bon week-end Julio.
0
ThWilliam Messages postés 418 Date d'inscription mardi 3 janvier 2006 Statut Membre Dernière intervention 26 novembre 2013 4
6 nov. 2009 à 22:05
Salut zwyx,

Et non, la moulinette de Delphi n'y est pour rien.
Ce sont tes alignements qui causent problèmes.

PnlA1.Align :alClient -> sa hauteur la hauteur de la zone client de GbXa. C'est une erreur, car il est masqué en partie par les 3 autres panels.
Les 3 autres panels sont alignés alBottom.

Il faut savoir que Delphi repositionne les composants dans l'ordre de leur création.
Quand un composant est aligné alBottom et qu'on fait un resize, c'est la valeur Top du composant qui s'adapte.
Ex : après un resize, la zone client de Gbxa augmente de 300 -> Chaque Top des panel 2,3,4 augmente de 300. Pas de problèmes.

Mais dans ton événement OnResize, tu modifies la hauteur de PnlA2 (= PnlA1 div 2). Ici, en augmentant le top de 300, il est possible que le composant ne puisse plus être positionné en entier. Donc, adaptation du Top pour pouvoir loger le tout aligné en bas. Maintenant, il faut repositionner PnlA3, mais il n'y a plus de place en bas, donc il vient au-dessus de PnlA2 !!!

Désolé pour cette explication qui n'est pas très scientifique...

Si tu veux que la hauteur de PnlA2 soit toujours la moitié de celle de PnlA1, voici une solution :

PnlA1.Align:= alNone;
PnlA1.Anchors:= [akLeft, akTop];
PnlA2.Align:= alNone;
PnlA2.Anchors:= [akLeft];
PnlA3.Align:= alBottom;
PnlA4.Align:= alBottom;

(bien sûr, tu peux rajouter akRight dans les Anchors)

procedure TForm1.FormResize(Sender: TObject);
var
H: integer;
begin
H:= PnlA3.Top - PnlA1.Top; // calcul de la zone pour panel 1 et 2
PnlA1.Height:= H div 3 * 2;
PnlA2.Height:H - PnlA1.Height; // la hauteur de pnlA2 le reste de la zone
PnlA2.Top:= PnlA1.Top + PnlA1.Height;
end;

Remarque : pour le redimensionnement de PnlA2, tu peux utiliser SetBounds (moins de scintillement)

A +
Thierry
0
ThWilliam Messages postés 418 Date d'inscription mardi 3 janvier 2006 Statut Membre Dernière intervention 26 novembre 2013 4
7 nov. 2009 à 12:45
Salut Delphiprog,

Je teste toujours mes solutions avant de les poster... et celle-ci marche (Delphi7).
Peut-être as-tu oublié de placer les 4 panels dans un GroupBox qui est aligné alLeft (soit Anchors = [akLeft, akTop, akBottom].

Quant à l'explication, je suis désolé si je me suis mal exprimé. Mais ce n'est pas simple ! C'est en faisant des tests avec divers alignements et en testant les propriétés Top et Height des Panels que j'en suis arrivé à cette tentative d'explication. Je dis bien "tentative".

Cordialement
Thierry
0
cs_Delphiprog Messages postés 4297 Date d'inscription samedi 19 janvier 2002 Statut Membre Dernière intervention 9 janvier 2013 32
7 nov. 2009 à 13:37
@thierry : no problemo. Ce n'était pas facile à expliquer, il faut bien le reconnaitre. Néanmoins, la solution que tu proposes me parait bien compliquée et un peu...alambiquée. De mon côté, je n'ai rien changé à la disposition ni aux propriétés des TPanel, hormis PnlB1 et PnlB2 car nous ne savons rien du reste de son application. Zwyx a précisé que le code fourni était un exemple pour nous permettre de lui trouver une solution.
Cela dit, après c'est à chacun de faire le choix de la solution qu'i préfère.
Bonne continuation à tous.

8000 Lévriers 'galgos' par an sont torturés et massacrés en Espagne
May Delphi be with you

Pensez à cliquer sur Réponse acceptée lorsque la réponse vous convient.
0
Rejoignez-nous