mercredi 17 juin 2009

GridBagLayout (suite)

J'ai refait du Java aujourd'hui, et j'ai finalement essayé ce dont je parlais l'autre jour (la classe GridBagLayout).

En Java, pour placer des trucs dans une fenêtre, il faut le "programmer" (versus simplement placer les éléments avec la souris & ses mains). Java offre plusieurs gestionnaires d'interface graphique (à part la possibilité de tout faire soi-même, ce qui s'avère généralement compliqué). Si je n'en oublie pas, ça ressemble à ceci:

  • BorderLayout (défaut)
  • FlowLayout
  • CardLayout
  • GridLayout
  • BoxLayout
  • GridBagLayout


Ils ont tous des caractéristiques assez intéressantes. BorderLayout comprend 5 "endroits" (North, South, East, West, ainsi que Center (le centre occupe tout l'espace disponible, les autres occupant l'espace minimal)). On se sert de lui pour placer par exemple une barre d'outils (North) et "le reste" (Center). FlowLayout place les objets l'un à la suite de l'autre sur une ligne, et change de ligne quand il n'a plus d'espace. GridLayout place les éléments dans des cellules d'un tableau (remarque: toutes les cellules sont identiques en termes de taille). BoxLayout est bizarre et fucké et je ne l'utilise pas (jusqu'à présent).

Ils sont tous faciles à utiliser.

GridBagLayout, lui, c'est beaucoup plus compliqué.


Il y a fondamentalement deux choses à savoir concernant les gestionnaires:

  • On peut insérer des "panneaux" (qui jouent le rôle de composants normaux), lesquels peuvent également incorporer un gestionnaire de mise en forme (différents de la fenêtre qui les accueille)
  • Chaque composant a des propriétés, notamment PreferredSize, MinimumSize, et MaximumSize. Ces propriétés ne sont pas nécessairement utilisées; ça dépend du gestionnaire.



Malheureusement, souvent les gestionnaires "simples" ne suffisent pas. Par exemple, j'ai essayé de créer un formulaire où les éléments étaient alignés, et où il y avait des champs de texte ainsi que des boîtes combo. Le problème était que les boîtes combo étaient plus grosses que les autres éléments, et c'était donc elles qui fixaient la taille des cellules. De plus, les éléments occupaient tout l'espace disponible (propriété du gestionnaire), de telle sorte que les champs de texte étaient rendus beaucoup trop gros (bien au-delà de leur PreferredSize).


GridBagLayout

GridBagLayout permet de créer un tableau de n'importe combien de lignes et de colonnes, et où les composants peuvent occuper plus d'une cellule, dans la direction que l'on précisera (ligne, colonne, ligne et colonne). La largeur et la hauteur d'une cellule est déterminée principalement par la largeur et la hauteur maximale observée dans les cellules d'une même colonne et d'une même ligne (respectivement). Ça devient un peu compliqué quand on ne veut pas que les cellules soient trop grandes mais que le tableau contient des choses qui sont difficiles à aligner. Il y a quand même des moyens de contourner les problèmes (par exemple avec des panneaux).

En gros, on doit obtenir un objet de type GridBagConstraints, lequel on passe en argument lors de l'ajout du composant au gestionnaire de mise en forme. On modifie alors, pour chaque composant voulu, les champs gridx et gridy de la classe GridBagConstraints, qui sont les coordonnées de l'objet dans le tableau ((0,0) étant en haut à gauche).

De plus, il y a beaucoup d'options. On peut décider pour chaque cellule l'alignement du composant à l'intérieur, si le composant est étiré ou non pour occuper l'espace disponible (si oui, on peut décider si c'est horizontalement, verticalement, ou les deux). On peut rajouter du padding, des affaires de même. Oh, il y a quelque chose qui permet de distribuer "proportionnellement à une importance donnée" l'espace libre dans la fenêtre, si on souhaite que les composants occupent tout l'espace de la fenêtre.

En tout cas, c'est assez compliqué, mais ça vaut la peine.

Voici le code que j'ai écrit (que je viens tout juste de terminer de modifier), ainsi que le résultat que ça donne (remarquez que j'ai abandonné la dernière ligne et je me suis résigné à placer tout son contenu dans un panneau... j'avais des problèmes d'espacement).

panDetails = new JPanel(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();

c.anchor = GridBagConstraints.LINE_END;
c.insets = new Insets(2,4,2,4);
c.gridx = 0; // première colonne
c.gridy = 0; panDetails.add(labelNom,c);
c.gridy = 1; panDetails.add(labelTel,c);
c.gridy = 2; panDetails.add(labelCell,c);
c.gridy = 3; panDetails.add(labelEmail,c);
c.gridy = 4; panDetails.add(labelFete,c);

c.anchor = GridBagConstraints.LINE_START; c.gridwidth = 5;
c.gridx = 1; // deuxième colonne & suivantes

c.gridy = 0; panDetails.add(txtNom,c); // première ligne

c.gridy = 1; c.gridwidth = 1; // deuxième ligne
c.gridx = 1; panDetails.add(txtTel1,c);
c.gridx = 3; panDetails.add(txtTel2,c);
c.gridx = 5; panDetails.add(txtTel3,c);
c.gridx = 2; panDetails.add(new JLabel("-"),c);
c.gridx = 4; panDetails.add(new JLabel("-"),c);

c.gridy = 2; // troisième ligne
c.gridx = 1; panDetails.add(txtCell1,c);
c.gridx = 3; panDetails.add(txtCell2,c);
c.gridx = 5; panDetails.add(txtCell3,c);
c.gridx = 2; panDetails.add(new JLabel("-"),c);
c.gridx = 4; panDetails.add(new JLabel("-"),c);

c.gridx = 1; c.gridy = 3; c.gridwidth = 5; // quatrième ligne
panDetails.add(txtEmail,c);

c.gridy = 4; c.gridwidth = 5; // cinquième ligne
panCombos = new JPanel(new FlowLayout());
panCombos.add(comboJour); panCombos.add(comboMois);
panCombos.add(comboAnnee);
c.gridx = 1;
panDetails.add(panCombos,c);


Aucun commentaire: