II. Gestion de l'espace▲
Les widgets sont placés à l'écran par un gestionnaire d'espace. Celui-ci détermine leur position et taille sur la fenêtre d'affichage. Il existe plusieurs gestionnaires d'espace en Perl/Tk : pack, place et grid.
Ces trois gestionnaires sont appelés comme des méthodes sur le widget, mais ils ont tous leurs propres méthodologies et arguments pour modifier l'emplacement et la façon, dont les widgets sont placés à l'écran
$widget1-
>
pack
(); $widget2-
>
place(); $widget3-
>
grid();
Lorsqu'on organise des widgets, il est souvent nécessaire de distinguer des groupes de widgets pour obtenir un look and feel particulier. Quand on utilise pack, par exemple, il est difficile d'empiler horizontalement et verticalement les widgets sans les grouper d'une façon ou d'une autre. On rassemble les widgets en utilisant un widget cadre dans une fenêtre ou en utilisant une autre fenêtre (un widget de premier niveau).
On crée notre première fenêtre en appelant MainWindow. Une MainWindow est une forme spéciale de widget de premier niveau. Pour plus de détails sur la création et la configuration des widgets cadre et de premier niveau, voir le chapitre 12, Cadres, et le chapitre 13, Widgets de premier niveau.
Par suite des différences existant entre les trois gestionnaires d'espace, il est difficile (pas complètement impossible, mais vraiment pas recommandé) d'utiliser plus d'un gestionnaire dans la même zone. Dans notre $mw
, on peut afficher plusieurs types de widgets mais, si l'on commence à utiliser pack, il faut continuer à le faire pour tous les widgets directement contenus dans $mw
. On ne pourrait utiliser grid au milieu de tout cela. Une fenêtre pouvant contenir un cadre qui, à son tour, contient d'autres widgets, nous utilisons pack pour placer le cadre dans la fenêtre principale, puis nous pouvons utiliser grid pour gérer les widgets dans le cadre.
Bien que les différents gestionnaires d'espace aient chacun leurs forces et faiblesses, pack est le plus utilisé et c'est donc lui que je traiterai en premier et de façon détaillée. grid était en cours de développement pendant l'écriture de ce livre, et a beaucoup évolué avec la sortie de Tk8.0 et son portage en Perl. Le gestionnaire place est le plus difficile à utiliser car vous devez connaître les coordonnées exactes de chaque widget.
II-A. Pack▲
Vous vous rappelez, lorsque vous étiez enfant et que vous deviez assembler ces puzzles en bois ? Ils arboraient souvent de jolies images d'animaux et chaque pièce ne pouvait se trouver que dans un seul emplacement. Les chevauchements entre pièces n'étaient pas possibles.
Avec le gestionnaire d'espace pack, nos fenêtres ressemblent à ces puzzles en bois car les widgets ne peuvent pas non plus se chevaucher ou se recouvrir (partiellement ou complètement). Voyez la figure 2.2.
Si un bouton est placé à un certain endroit de la fenêtre, le bouton suivant (ou tout autre widget) devra se placer à côté du bouton déjà présent. Heureusement, nos fenêtres ne s'occuperont que de formes rectangulaires, et pas de pièces de puzzle aux formes exotiques.
L'ordre selon lequel on place ses widgets est très important car il affecte directement ce que l'on verra à l'écran. Chaque widget cadre, ou fenêtre, gère une liste des objets qui s'affichent chez lui. Cette liste est ordonnée : si le widget A précède le widget B, A sera prédominant. Cela deviendra évident lorsque nous passerons plusieurs exemples en revue. Nous obtiendrons souvent un aspect très différent pour notre fenêtre, simplement en plaçant les widgets dans un autre ordre.
Si vous ne vous souciez pas de ce à quoi peut ressembler la fenêtre, ni de comment sont placés les widgets, vous pouvez utiliser pack sans argument et ne pas lire le reste de ce chapitre. Voici à nouveau comment faire :
$widget-
>
pack
();
Pour donner un plus bel aspect à vos fenêtres et les rendre plus faciles à utiliser (et plus conviviales), vous pouvez passer des paramètres à la méthode pack afin de modifier la façon dont les widgets et la fenêtre apparaîtront. Comme toujours en Perl/Tk, les arguments sont organisés par paires. Une utilisation plus sophistiquée serait donc :
$widget-
>
pack
( [option =>
valeur, ...] );
Voici un exemple de code créant une fenêtre en n'utilisant aucune des options de pack. La figure 2.3 présente le résultat obtenu (je sais que je n'ai pas encore traité tous les widgets utilisés dans cet exemple mais patientez, c'est très simple).
#!/usr/bin/perl -w
use Tk;
my $mw
=
MainWindow->
new;
$mw-
>
title("Fenêtre moche"
);
$mw-
>
Label( -
text =>
"Voici un exemple de fenêtre moche
\n
obtenue sans passer d'option à pack"
)->
pack
;
$mw-
>
Checkbutton( -
text =>
"J'aime ça !"
)->
pack
;
$mw-
>
Checkbutton( -
text =>
"J'ai horreur de ça !"
)->
pack
;
$mw-
>
Checkbutton( -
text =>
"Je m'en moque"
)->
pack
;
$mw-
>
Button(
-
text =>
"Fin"
,
-
command =>
sub {
exit;
}
)->
pack
;
MainLoop;
Vous pouvez modifier le code précédent et ajouter quelques options aux appels à pack afin de donner un plus bel aspect à votre fenêtre (examiner la figure 2.4) :
#!/usr/bin/perl -w
use Tk;
my $mw
=
MainWindow->
new;
$mw-
>
title("Belle fenêtre"
);
$mw-
>
Label( -
text =>
"Exemple de fenêtre moins disposée au hasard et obtenue en passant des options à pack"
)->
pack
;
$mw-
>
Button(
-
text =>
"Fin"
,
-
command =>
sub {
exit;
}
)->
pack
(
-
side =>
'bottom'
,
-
expand =>
1
,
-
fill =>
'x'
);
$mw-
>
Checkbutton( -
text =>
"J'aime ça !"
)->
pack
(
-
side =>
'left'
,
-
expand =>
1
);
$mw-
>
Checkbutton( -
text =>
"J'ai horreur de ça !"
)->
pack
( -
side =>
'left'
, -
expand =>
1
);
$mw-
>
Checkbutton( -
text =>
"Je m'en moque"
)->
pack
(
-
side =>
'left'
,
-
expand =>
1
);
MainLoop;
L'utilisation de pack vous permet de contrôler :
- la position dans la fenêtre par rapport aux bords du cadre ou de celle-ci ;
- la taille des widgets, relativement aux autres widgets ou de façon absolue ; l'espacement entre les widgets ;
- la position dans la liste des widgets de la fenêtre ou du cadre.
Les options et valeurs par défaut sont énumérées et étudiées dans la section suivante.
II-A-1. Options de pack▲
La liste suivante énumère toutes les options disponibles lors d'un appel à pack. Les valeurs par défaut sont mises en gras (ce qui signifie que, si vous n'utilisez pas cette option, vous obtiendrez les effets de cette valeur pour cette option).
-side => 'left' | 'right' | 'top' | 'bottom'
- Place le widget contre le bord spécifié de la fenêtre ou du cadre.
-fill => 'none' | 'x' | 'y' | 'both'
- Force le widget à remplir dans la direction spécifiée le rectangle qui lui a été alloué.
-expand => 1 | 0
- Force le rectangle alloué au widget à remplir l'espace disponible restant dans la fenêtre ou le cadre.
-anchor => 'n' | 'ne' | 'e' | 'se' | 's' | 'sw' | 'w' | 'nw' | 'center'
- Ancre le widget dans le rectangle qui lui a été alloué.
-after => $autrewidget
- Met $widget après
$autrewidget
dans l'ordre de placement.
-before => $autrewidget
- Met $widget avant
$autrewidget
dans l'ordre de placement.
-in => $autrefenetre
- Place
$widget
dans$autrefenetre
au lieu de le mettre dans le parent de$widget
, ce qui est le cas par défaut.
-ipadx => montant
- Augmente la dimension horizontale du widget par montant x 2.
-ipady => montant
- Augmente la dimension verticale du widget par montant x 2.
-padx => montant
- Place des espaces de remplissage à gauche et à droite du widget.
-pady => montant
- Place des espaces de remplissage au-dessus et en dessous du widget.
II-A-2. Positionnement des widgets▲
Chaque fenêtre (ou cadre) a quatre côtés haut, bas, gauche et droite. Le placeur utilise ces bords comme points de référence pour les widgets. Par défaut pack place les widgets contre le haut de la fenêtre ou du cadre.
Vous pouvez choisir le bord contre lequel sera placé un widget en utilisant l'option -side :
-
side =>
'left'
|
'right'
|
'top'
|
'bottom'
Si, par exemple, vous souhaitez placer votre bouton contre le bord gauche de la fenêtre, vous pouvez préciser -
side =>
'left'
.
En utilisant notre exemple « Bonjour tout le monde » comme base, voyons ce qui se passe lorsque l'on place notre bouton contre les différents bords (figure 2.5).
La seule chose qui changera sera la partie ->pack de la ligne de création du bouton. Nous modifierons aussi la chaîne « Bonjour tout le monde » dans l'instruction $mw-
>
title afin de montrer l'option de pack utilisée.
La forme employée est :
$mw-
>
Button(
-
text =>
'Fin'
,
-
command =>
sub {
exit;
}
)->
pack
( -
side =>
'POSITIONNEMENT'
);
où POSITIONNEMENT peut être top, bottom, left ou right.
Les fenêtres montrées ici ont été légèrement agrandies pour mettre en évidence les différences résultant de l'utilisation des diverses valeurs de -side. Normalement, la fenêtre sera seulement de la taille requise pour afficher le bouton. Lorsque vous décidez de la façon de placer les widgets, il est toujours préférable de voir ce qui se passe lorsque vous agrandissez ou réduisez la fenêtre. Assurez-vous que le comportement obtenu est celui recherché.
Pour l'instant pack semble assez simple, mais qu'en est-il si vous souhaitez placez plus d'un bouton dans votre application ? Que se passe-t-il si l'on ajoute simplement d'autres boutons ?
$mw-
>
Button( -
text =>
'Fin 1'
, -
command =>
sub {
exit; }
)->
pack
;
$mw-
>
Button( -
text =>
'Fin 2'
, -
command =>
sub {
exit; }
)->
pack
;
$mw-
>
Button( -
text =>
'Fin 3'
, -
command =>
sub {
exit; }
)->
pack
;
$mw-
>
Button( -
text =>
'Fin 4'
, -
command =>
sub {
exit; }
)->
pack
;
Comme la valeur par défaut de -side est top, on s'attend à ce qu'ils soient tous entassés contre le haut de la fenêtre ; n'est-ce pas ? C'est un peu ça. Le placeur alloue de l'espace pour chaque widget, puis manipule le widget dans cet espace, et cet espace dans la fenêtre.
La figure 2.6 montre à quoi ressemble la fenêtre avec les quatre boutons « Fin » ; la section suivante explique pourquoi ils sont placés ainsi.
II-A-3. Rectangles alloués▲
Lorsqu'il doit placer un widget, le placeur recherche d'abord le bord (haut, bas, droite, gauche) à utiliser. Puis, il réserve une zone rectangulaire invisible sur toute la longueur de ce bord pour ne l'utiliser qu'avec ce widget.
Dans la figure 2.7, le rectangle en trait continu représente notre fenêtre (ou cadre) vide et le rectangle en pointillé est la zone rectangulaire que le placeur réserve pour le premier bouton. En réalité, il occupe toute la largeur ou la hauteur de la fenêtre, mais pour mieux le mettre en évidence, nous l'avons un peu indenté.
Les dimensions de la boîte en pointillé, que nous appellerons le rectangle alloué, sont calculées d'après la taille du widget. Pour les bords haut et bas, le rectangle alloué est aussi large que la fenêtre et aussi haut que le widget qui y sera placé, mais pas plus. Pour les bords droit et gauche, ce rectangle est aussi haut que la fenêtre, et aussi large qu'il est nécessaire pour convenir au widget, mais pas plus.
Jusqu'à maintenant, nos exemples ont utilisé des boutons dans lesquels le texte du bouton détermine sa largeur. Si nous créons un bouton contenant le texte « Fin », et un autre avec le texte « Fin, Terminé, Stop », ce second bouton sera beaucoup plus large que le premier. Lorsque ces deux widgets seront placés contre le bord gauche ou droit de la fenêtre, le second bouton aura un rectangle alloué plus large que celui du premier. Si nous les plaçons tous les deux contre les bords haut et bas, les rectangles alloués seront de la même hauteur et de la même largeur car cette dernière est déterminée par la fenêtre, pas par le widget.
Lorsque la taille du rectangle alloué a été déterminée, le widget est placé à l'intérieur selon les options utilisées et/ou les valeurs par défaut de ces options. Je passerai plus tard en revue ces options et la façon dont elles affectent le rectangle alloué.
Une fois que le premier widget a été placé dans la fenêtre, la taille de la zone disponible pour les rectangles suivants est plus petite car le premier rectangle alloué a utilisé une partie de cet espace (voir la figure 2.8).
Quand plusieurs boutons sont placés contre les différents bords de la même fenêtre, les résultats dépendent de l'ordre utilisé.
Nous commencerons par placer un bouton en haut, un autre en bas, et les autres à droite et à gauche :
$mw-
>
Button( -
text =>
"HAUT"
, -
command =>
sub {
exit }
)->
pack
( -
side =>
'top'
);
$mw-
>
Button( -
text =>
"BAS"
, -
command =>
sub {
exit }
)->
pack
( -
side =>
'bottom'
);
$mw-
>
Button( -
text =>
"DROIT"
, -
command =>
sub {
exit }
)->
pack
( -
side =>
'right'
);
$mw-
>
Button( -
text =>
"GAUCHE"
, -
command =>
sub {
exit }
)->
pack
( -
side =>
'left'
);
Les rectangles alloués pour cette fenêtre ressembleront à ceux du schéma de la figure 2.9.
II-A-4. Remplissage du rectangle alloué▲
Normalement, le widget est laissé à sa taille par défaut, qui est habituellement plus petite que le rectangle qui lui a été alloué. Si l'option -fill est utilisée, le widget changera lui-même de taille pour remplir le rectangle alloué en fonction de la valeur indiquée. Les valeurs possibles sont :
- -fill => 'none' | 'x' | 'y' | 'both'
L'utilisation de la valeur 'x' modifiera la taille du widget selon l'axe des x. De même, 'y' fera que le widget s'agrandira selon l'axe des y. -f1ll => 'both' est un bon moyen de voir exactement la taille et l'emplacement donné au rectangle car 'both' modifie la taille du widget dans les directions x et y. Reprenons notre exemple des quatre boutons, en précisant -fill => 'both' :
$mw-
>
Button( -
text =>
"HAUT"
, -
command =>
sub {
exit }
)->
pack
( -
side =>
'top'
, -
fi11 =>
'both'
);
$mw-
>
Button( -
text =>
"BAS"
, -
command =>
sub {
exit }
)->
pack
( -
side =>
'bottom'
, -
fi11 =>
'both'
);
$mw-
>
Button( -
text =>
"DROIT"
, -
command =>
sub {
exit }
)->
pack
( -
side =>
'right'
, -
fill =>
'both'
);
$mw-
>
Button( -
text =>
"GAUCHE"
, -
command =>
sub {
exit }
)->
pack
( -
side =>
'left'
, -
fi11 =>
'both'
);
La figure 2.11 montre la fenêtre que l'on obtient.
Si nous inversons le bouton que nous créons en premier, nous obtenons un résultat différent. La fenêtre de la figure 2.12 a été créée en plaçant les widgets dans l'ordre droit, gauche, haut et bas.
La figure 2.13 est le résultat d'encore un autre ordonnancement, qui montre bien que les rectangles alloués changent de taille selon ce qui est placé en premier.
Une utilisation classique de -fill est avec les widgets utilisant des barres de défilement : les boîtes de liste, les canevas et les textes. Habituellement, les barres de défilement se trouvent sur le côté de la fenêtre et l'on souhaite que la boîte de liste remplisse la zone restante. Voyez le chapitre 6, Barres de défilement, et le chapitre 7, Le widget boîte de liste, pour plus d'informations.
II-A-5. Agrandissement du rectangle alloué▲
L'option -expand manipule le rectangle alloué, non le widget qu'il contient. La valeur associée à -expand est un booléen.
- -expand => 1 | 0
Avec une valeur vraie, le rectangle alloué s'agrandira dans tout l'espace disponible restant dans la fenêtre selon le bord sur lequel le widget a été placé.
Les widgets placés sur les bords droit ou gauche s'agrandiront selon l'axe horizontal. Ceux placés sur les bords haut ou bas s'agrandiront dans la direction verticale. Si plus d'un widget est placé avec l'option -expand positionnée, l'espace supplémentaire dans la fenêtre est divisé à parts égales entre tous les rectangles alloués qui le veulent.
Dans les figures 2.10 ou 2.11, nous avons constaté qu'il restait un peu de place au centre de la fenêtre et qu'il n'était occupé par aucun widget. Si nous modifions le code et que nous ajoutons -expand => 1 à la liste des options de pack pour chaque bouton, le résultat sera celui affiché par la figure 2.14.
Remarquez que la figure 2.14 laisse l'option -fill => 'both' dans le code. Si nous omettons l'option -fill, les boutons garderont leur taille originale, mais les rectangles alloués (invisibles) s'étendront sur l'espace restant dans la fenêtre (voir la figure 2.15).
Dans la figure 2.15, les boutons sont centrés dans leurs rectangles alloués à cause de la valeur par défaut de l'option -anchor, qui est 'center'.
II-A-6. Ancrage d'un widget dans son rectangle alloué▲
L'option -anchor manipule le widget à l'intérieur du rectangle alloué en l'ancrant à l'endroit indiqué par la valeur de l'option. Elle utilise les points cardinaux comme références.
- -anchor => 'e' | 'w' | 'n' | 's' | 'ne' | 'nw' | 'se' | 'sw' | 'center'
La figure 2.16 montre ces emplacements dans un exemple de rectangle alloué.
La valeur par défaut de -anchor est 'center', qui place le widget au centre du rectangle qui lui a été alloué. À moins que l'option -expand n'ait une valeur vraie, cela ne changera pas grand-chose à quoi que ce soit dans la fenêtre. Ainsi que nous l'avons vu dans la figure 2.17, qui montre l'effet de l'utilisation de l'option -expand => 1, il est évident que le widget colle à cette position centrale lorsque la fenêtre change de taille.
La figure 2.18 montre ce que donnent -
anchor =>
'e'
et -
anchor =>
'w'
si toutes les autres valeurs par défaut sont utilisées pour placer le widget.
Rappelez-vous que le rectangle alloué est créé en fonction du bord contre lequel est placé le widget, certaines combinaisons sembleront donc n'avoir aucun effet. Par exemple :
->
pack
(-
side =>
'top'
, -
anchor =>
'n'
);
Ce bout de code laissera le widget exactement au même endroit qu'il aurait été si l'option -anchor n'avait pas été précisée car le rectangle alloué ne change pas du tout de taille. Si l'option -expand est aussi utilisée, le widget collera au côté nord de la fenêtre lorsque la taille de celle-ci sera modifiée. Si -
anchor =>
's'
avait été utilisée, le widget aurait collé au côté sud de la fenêtre lors du changement de taille de celle-ci.
L'option -anchor est le plus souvent utilisée pour aligner plusieurs widgets d'un coup. Les figures 2.19 et 2.20 montrent deux exemples classiques.
Parfois, lorsque -side et -anchor sont utilisées ensemble, les résultats ne semblent pas être ceux attendus. Gardez toujours à l'esprit ce rectangle alloué invisible et la façon dont il affecte ce que vous voyez à l'écran.
II-A-7. Ordonnancement des widgets dans une fenêtre▲
Chaque fenêtre contenant des widgets garde la trace de ceux-ci dans une liste ordonnée. L'ordre de cette liste est normalement déterminé par celui dans lequel les widgets ont été placés. Le dernier placé est le dernier de la liste. En utilisant l'option -after, on peut modifier l'ordre par défaut en spécifiant après quel widget sera placé notre nouveau widget. À l'opposé, si l'on utilise l'option -before, on peut placer le nouveau widget avant un autre déjà placé :
-
after =>
$autrewidget
-
before =>
$autrewidget
Créons, par exemple, quatre boutons ($widget1, $widget2, $widget3, $widget4) et
plaçons-en trois pour commencer. L'appel de pack pour $widget4 pourrait alors être :
$widget4-
>
pack
(-
after =>
$widget1
);
La figure 2.21 montre deux fenêtres : l'une avant que $widget4 ne soit placé, l'autre après.
Pour placer $widget4 devant $widget1, on utilisera l'instruction :
$widget4-
>
pack
(-
before =>
$widget1
);
Nous en constatons les effets sur la figure 2.22.
II-A-8. Compléter la taille d'un widget avec des espaces de remplissage▲
Le dernier moyen de forcer pack à modifier la taille du widget est d'utiliser les options de remplissage. Le premier ensemble de ces options affecte le widget lui-même en ajoutant quelque chose à sa taille par défaut. Des montants différents ou identiques peuvent être ajoutés dans les directions x et y. Pour préciser le remplissage voulu dans la direction x, on utilise l'option -ipadx :
-
ipadx =>
montant
On spécifie le remplissage dans la direction y de cette façon :
-
ipady =>
montant
montant est un nombre représentant une distance d'écran. Je traiterai de la définition d'une telle distance dans la section suivante.
Les options -ipadx et -ipady changent toutes les deux la taille du widget avant que le rectangle alloué ne soit calculé. -ipadx ajoute le montant spécifié à gauche et à droite du widget. La largeur totale du widget augmentera donc de (montant x 2). La figure 2.23 montre les effets des options -ipadx et -ipady sur un bouton.
L'autre type de remplissage est effectué entre le bord du widget et celui du rectangle alloué. Il est réalisé avec les options -padx et -pady :
-
padx =>
montant
-
pady =>
montant
L'utilisation de -padx et -pady n'affecte pas la taille du widget mais celle du rectangle alloué. Ces options agissent comme un tampon placé autour du widget, l'empêchant de toucher les autres widgets. La figure 2.24 montre les effets de leur utilisation.
Un bon moyen de se rappeler la différence entre -ipadx/y et -padx/y est que le « i » signifie « intérieur du widget » ou « remplissage interne ».
II-A-9. Distances d'écran▲
Vous verrez souvent des options, comme -ipadx et -ipady, nécessitant des valeurs indiquées en unités d'écran (ce que l'on appelle une distance d'écran). Vérifiez toujours la valeur que demande réellement l'option. Une unité d'écran est un nombre suivi de l'unité utilisée (par défaut : le pixel).
Désignation |
Signification |
Exemples |
---|---|---|
(aucune) |
Pixels (défaut) |
20, 30, "20", "40" |
c |
Centimètres |
'3c', '4c', "3c" |
i |
Pouces (Inches) |
'2i', "3i" |
m |
Millimètres |
'4m', "4m" |
p |
Points imprimante (1/72 pouce) |
"72p", '40p' |
Pour utiliser ces désignations, il faut mettre la valeur entre apostrophes (simples ou doubles). Voici quelques exemples :
$bouton-
>
pack
( -
ipadx =>
20
); # 20 pixels
$bouton-
>
pack
( -
ipadx =>
'20'
); # encore 20 pixels
$bouton-
>
pack
( -
ipadx =>
"1i"
); # 1 pouce
$bouton-
>
pack
( -
ipadx =>
'1m'
); # 1 millimètre
$bouton-
>
pack
( -
ipadx =>
1
); # 1 pixel
$bouton-
>
pack
( -
ipadx =>
"20p"
); # 20 points imprimante
Rappelez-vous que la désignation "p"
ne signifie ni « pixel », ni « pouce », mais « point imprimante ». Je vous recommande de toujours utiliser les pixels comme unité de mesure car des écrans différents ont des résolutions différentes ; un écran donné peut afficher un vrai pouce et un autre peut afficher autre chose.
II-A-10. Affichage dans un autre parent▲
Par défaut, lorsqu’un widget est placé, il l'est dans la région qui l'a créé, mais il est parfois nécessaire de l'afficher dans une autre région. Pour ce faire, on utilise l'option -in :
-
in =>
$autrefenêtre
Celle-ci place le nouveau widget à la fin de la liste de placement d'$autrefenêtre
et l'affiche en fonction de cela. Toutes les autres options précisées lors de l'appel à pack s'appliquent quand même.
II-A-11. Méthodes associées à pack▲
Quelques méthodes sont utilisées en conjonction avec le gestionnaire d'espace pack. Elles permettent au programmeur d'obtenir des informations sur le widget placé, ou sur le widget parent contenant d'autres widgets.
II-A-12. Suppression d'un widget▲
Pour supprimer un widget d'une fenêtre ou d'un cadre, on utilise la méthode packForget :
$widget-
>
packForget();
PackForget fait comme si le widget disparaissait. Il n'est pas détruit, mais n'est plus géré par pack. Il est supprimé de la liste de placement et, s'il doit être replacé plus tard, il sera mis à la fin de cette liste.
II-A-13. Obtention d'informations sur les emplacements▲
Pour récupérer la liste de toutes les informations sur la configuration de l'emplacement d'un widget placé par pack, on utilise packInfo :
@liste
=
$widget-
>
packInfo();
Cette liste est une suite de paires option/valeur. La première paire est -in avec la fenêtre contenant le widget (habituellement le parent). Voici un exemple d'informations retournées par packInfoo :
-
in MainWindow=
HASH(Ox8l8dcf4) -
anchor n -
expand O -
fill none
-
ipadx 0
-
ipady 0
-
padx 10
-
pady 10
-
side left
On peut en déduire que nous avons placé notre $widget
dans la fenêtre principale plutôt que dans un cadre. Comme la liste est appariée, nous pourrions aisément stocker le résultat de packlnfo dans un hachage et faire référence aux différentes options en utilisant une clé de ce hachage :
%infos_placement
=
$widget-
>
packInfo;
print
"Bord utilisé : "
, $infos_placement
{-
side}
, "
\n
"
;
II-A-14. Désactivation et activation du changement de taille automatique▲
Lorsque l'on place un widget dans une fenêtre, celle-ci (ou le cadre) modifiera elle-même sa taille pour qu'elle convienne au widget. Si vous placez dynamiquement des widgets dans votre fenêtre au cours de l'exécution du programme, la fenêtre semblera sauter de taille en taille. Vous pouvez désactiver ce comportement en utilisant la méthode packPropagate sur le cadre ou le widget de premier niveau :
$widget-
>
packPropagate(0
);
Si on lui passe la valeur 0 ou 'off', packPropagate modifie le comportement du widget pour qu'il ne modifie pas sa taille afin de tenir compte de widgets qu'il contient. Lorsqu'une valeur fausse est passée à packPropagate avant que les widgets ne soient placés, le changement automatique de taille n'est pas assuré ; vous ne pouvez donc pas voir les widgets placés dans le parent tant que vous n'avez pas modifié explicitement la taille de ce dernier. Si vous appelez packPropagate après que les widgets ont été placés, votre widget ignorera toutes les modifications de taille venant de ses fils.
II-A-15. Énumération des widgets▲
On peut déterminer quels sont les widgets contenus dans notre cadre ou fenêtre avec la méthode packSlaves :
@liste
=
$widgetparent-
>
packSlaves();
packSlaves renvoie une liste ordonnée de tous les widgets ayant été placés dans $widgetparent
. Si ce dernier ne contient aucun widget placé par pack, cette méthode renvoie une chaîne (ou une liste) vide.
La liste renvoyée par packSlaves ressemble à celle-ci :
Tk::Button=
HASH(0x81b2970
) Tk::Button=
HASH(0x8116ccc
)
Tk::Button=
HASH(0x8lbcdd4)
Chaque élément est une référence à un widget placé par pack et peut être utilisé pour configurer celui-ci. On peut, par exemple, augmenter la taille de chaque widget de 20 pixels dans les deux directions en itérant sur chacun des éléments et en les « plaçant » avec cette nouvelle information. En reprenant notre exemple de « Belle fenêtre » de la figure 2.4, on peut ajouter un bouton qui appellerait packSlaves lorsqu'il est pressé :
#!/usr/bin/perl -w
use Tk;
my $mw
=
MainWindow->
new;
$mw-
>
title("Belle fenêtre"
);
$mw-
>
Label( -
text =>
"Exemple de fenêtre moins disposée au hasard et obtenue en passant des options à pack"
)->
pack
;
$mw-
>
Button(
-
text =>
"Agrandir"
,
-
command =>
\&
replace_fils
)->
pack
(
-
side =>
'bottom'
,
-
anchor =>
'center'
);
$mw-
>
Button(
-
text =>
"Fin"
,
-
command =>
sub {
exit; }
)->
pack
(
-
side =>
'bottom'
,
-
expand =>
1
,
-
fill =>
'x'
);
$mw-
>
Checkbutton( -
text =>
"J'aime ça !"
)->
pack
(
-
side =>
'left'
,
-
expand =>
1
);
$mw-
>
Checkbutton( -
text =>
"J'ai horreur de ça !"
)->
pack
(
-
side =>
'left'
,
-
expand =>
1
);
$mw-
>
Checkbutton( -
text =>
"Je m'en moque"
)->
pack
(
-
side =>
'left'
,
-
expand =>
1
);
MainLoop;
sub replace_fils {
my @fils
=
$mw-
>
packSlaves;
foreach (@fils
) {
$_
->
pack
( -
ipadx =>
20
, -
ipady =>
20
);
}
}
La figure 2.25 montre la fenêtre qui en résulte.
Voyons ce qui se passe lorsque l'on presse le bouton « Agrandir ». Comme le montre la figure 2.26, tous les widgets sont maintenant replacés avec les paramètres additionnels -
ipadx =>
20
, -
ipady =>
20
. Ces nouvelles options s'ajoutent à celles déjà utilisées lors du précédent placement des widgets. Si une option est répétée, la dernière prend le pas sur les précédentes.
La fenêtre devient subitement énorme ! Des pressions supplémentaires sur le bouton « Agrandir » n'auraient aucun effet sur la fenêtre, car tous les widgets ont déjà -ipadx
et -ipady à 20. Si l'on voulait toujours ajouter 20 aux valeurs d'-ipadx et -ipady, il faudrait récupérer les valeurs actuelles et leur ajouter 20. Voici le code réalisant cela :
sub replace_fils {
my @fils
=
$mw-
>
packSlaves;
foreach (@fils
) {
%infos_placement
=
$_
->
packInfo();
$_
->
pack
(
-
ipadx =>
20
+
$infos_placement
{
"-ipadx"
}
,
-
ipady =>
20
+
$infos_placement
{
"-ipady"
}
);
}
}
Nous utilisons packInfo pour récupérer la configuration courante, et nous ajoutons 20 aux valeurs concernées.
II-B. Grid▲
Le gestionnaire d'espace grid divise la fenêtre en une grille composée de lignes et colonnes débutant à 0,0 dans le coin supérieur gauche La figure 2.27 montre un exemple de grille.
Plutôt que d'utiliser les bords de la fenêtre comme points de référence, grid divise l'écran en lignes et colonnes Cela ressemble beaucoup à un tableur, n'est-ce pas ? Chaque widget est affecte à une cellule de la grille en utilisant les options de grid.
La méthode grid prend une liste de widgets au lieu de n'agir que sur un seul à la fois(10). En voici l'utilisation générique :
$widget1-
>
grid( [ $widget2
, ... , ][option =>
valeur ] );
Voici un exemple réel :
$widget1-
>
grid($widget2
, $widget3
);
Au lieu d'utiliser trois appels distincts, on peut n'utiliser qu'un seul appel à grid pour afficher les trois widgets. Vous pouvez aussi appeler indépendamment grid sur chaque widget, exactement comme avec pack. Chaque appel à grid créera une nouvelle ligne dans la fenêtre, ce qui fait que, dans notre exemple, $widget1
, $widget2
et $widget3
seront sur la première ligne. Un autre appel à grid aurait créé une seconde ligne ; c'est ce qui se passe lorsqu'on ne précise pas d'autres options à l'appel de grid.
Pour contrôler encore mieux vous pouvez préciser les options explicites -row et -column pour chaque widget de la fenêtre. Ces options seront traitées plus tard.
Lorsqu'aucune option supplémentaire n'est spécifiée, on suppose que :
- le premier widget de la ligne (
$widget1
dans notre exemple) appelle la méthode grid ; - tous les autres widgets de cette ligne seront spécifiés en paramètres de grid ;
- chaque appel supplémentaire de grid ajoutera une nouvelle ligne d'affichage ;
- des caractères spéciaux peuvent être utilisés pour changer les valeurs des options -columnspan et -rowspan du widget, sans utiliser ces options explicitement.
Quelques exemples nous aideront à comprendre. Chaque appel à grid crée une nouvelle ligne, nous obtiendrons donc deux lignes dans l'exemple suivant :
# Crée deux lignes, contenant chacune quatre widgets
$widget1-
>
grid($widget2
, $widget3
, $widget4
);
$widget5-
>
grid($widget6
, $widget7
, $widget8
);
Dans cet exemple, les quatre lignes ne contiennent chacune qu'un widget :
# Crée quatre lignes, chacune contenant un seul widget
$widgetl-
>
grid();
$widget2-
>
grid();
$widget3-
>
grid();
$widget4-
>
grid();
Nous pouvons aussi créer à mesure les widgets :
$mw-
>
Button( -
text =>
'Bouton 1'
, -
command =>
\&
fonctionl )->
grid(
$mw-
>
Button( -
text =>
'Bouton 2'
, -
command =>
\&
fonction2 ),
$mw-
>
Button( -
text =>
'Bouton 3'
, -
command =>
\&
fonction3 ),
$mw-
>
Button( -
text =>
'Bouton 4'
, -
command =>
\&
fonction4 )
);
Faites particulièrement attention au fait que les second, troisième et quatrième appels à Button se trouvent dans l'appel à grid. Les quatre boutons seront tous placés dans la première ligne. Si nous exécutions à nouveau la même instruction, les nouveaux widgets seraient placés dans la ligne suivante.
II-B-1. Caractères spéciaux▲
Différents caractères spéciaux peuvent servir à modifier la façon dont les widgets sont placés avec grid dans la fenêtre. Chacun d'eux sert de marqueur de place précisant que faire de cette position dans la grille :
"-" (le signe moins)
- Indique à grid que le widget spécifié juste avant ce signe dans la liste devra aussi s'étendre sur cette colonne. Pour s'étendre sur plus d'une colonne, mettez un « - » à chaque position étendant le widget. Un « - » ne peut suivre un« ^ » ou un « x ».
"x"
- Laisse un espace vide à l'endroit où un widget aurait normalement dû être placé.
"^"
- Un widget de la ligne x s'étendra sur les lignes x et x + 1 lorsque ce caractère est situé dans la liste des paramètres de grid pour la ligne s + 1 dans cette position ligne/colonne. Le nombre de caractères "^" doit correspondre au nombre de colonnes sur lesquelles s'étend le widget dans la ligne x. Cela ressemble au fonctionnement de "-", mais en vertical(11).
Les sections suivantes contiennent des exemples illustrant les effets de ces caractères spéciaux.
II-B-2. Traverser des colonnes▲
Le code suivant crée trois rangées de boutons. Les deux premières sont normales et, dans la troisième, le second bouton s'étend sur trois colonnes. Chaque caractère "-" incrémente le nombre de colonnes utilisées par le bouton qui est par défaut, de 1. Par conséquent, la colonne de départ et deux tirets ("-", "-") indiquent qu'il y a trois colonnes à traverser. L'option -sticky est nécessaire pour que le bouton colle aux bords des cellules qu'il traverse. Si cette option avait été omise, le bouton aurait été centré par rapport aux trois cellules traversées.
$mw-
>
Button(
-
text =>
"Bouton 1"
,
-
command =>
sub {
exit;
}
)->
grid(
$mw-
>
Button( -
text =>
"Bouton 2"
, -
command =>
sub {
exit }
),
$mw-
>
Button( -
text =>
"Bouton 3"
, -
command =>
sub {
exit }
),
$mw-
>
Button( -
text =>
"Bouton 4"
, -
command =>
sub {
exit }
)
);
$mw-
>
Button(
-
text =>
"Bouton 5"
,
-
command =>
sub {
exit;
}
)->
grid(
$mw
.->
Button( -
text =>
"Bouton 6"
, -
command =>
sub {
exit }
),
$mw-
>
Button( -
text =>
"Bouton 7"
, -
command =>
sub {
exit }
),
$mw-
>
Button( -
text =>
"Bouton 8"
, -
command =>
sub {
exit }
)
);
$mw-
>
Button(
-
text =>
"Bouton 9"
,
-
command =>
sub {
exit;
}
)->
grid( $mw-
>
Button( -
text =>
"Bouton 10"
, -
command =>
sub {
exit }
), -
sticky =>
"nsew"
);
La fenêtre résultante est celle de la figure 2.28.
II-B-3. Cellules vides▲
Le caractère "x" signifie « sauter cet espace » et laisser un trou dans la grille. Dans le code qui suit, on a supprimé la ligne qui créait « Bouton 6 » et on l'a remplacée par un "x". La cellule est encore présente, mais elle ne contient aucun widget.
$mw-
>
Button(
-
text =>
"Bouton 1"
,
-
command =>
sub {
exit;
}
)->
grid(
$mw-
>
Button( -
text =>
"Bouton 2"
, -
command =>
sub {
exit }
),
$mw-
>
Button( -
text =>
"Bouton 3"
, -
command =>
sub {
exit }
),
$mw-
>
Button( -
text =>
"Bouton 4"
, -
command =>
sub {
exit }
)
);
$mw-
>
Button( -
text =>
"Bouton 5"
, -
command =>
sub {
exit; }
)->
grid(
"x"
,
$mw-
>
Button( _text =>
"Bouton 7"
, -
command =>
sub {
exit }
),
$mw-
>
Button( -
text =>
"Bouton 8"
, -
command =>
sub {
exit }
)
);
Le résultat apparaît à la figure 2.29.
II-B-4. Options de Grid▲
Les options, autres que celles citées ci-dessous, fonctionnent comme celles de pack :
"-"
- Caractère spécial utilisé dans la liste de widgets de grid. Il augmente la valeur de l'option -colunnspan du widget qui se trouve avant lui dans la liste des widgets.
"x"
- Caractère spécial utilisé dans la liste de widgets de grid. Laisse un espace vide dans la grille.
"^"
- Caractère spécial utilisé dans la liste de widgets de grid. Il augmente la valeur de l'option -rowspan du widget qui se trouve directement au-dessus de lui dans la grille.
-column => n
- Indique la colonne où placer le widget (n ≥ 0).
-row => m
- Indique la ligne où placer le widget (m ≥ 0).
-columnspan => n
- Indique le nombre de colonnes à occuper par le widget à partir de -column.
-rowspan => m
- Indique le nombre de lignes à occuper par le widget à partir de -row.
-sticky => chaîne
- La chaîne contient les caractères n (« nord »), s (« sud »), e (« est ») ou w (« ouest ») Le widget collera à ces bords
-in => $autrefenetre
- Indique que le widget sera placé par grid dans
$autrefenetre
au lieu de l'être dans son parent.
-ipadx => montant
$widget
s'agrandit de 2 x montant dans la direction x.
-ipady => montant
$widget
s'agrandit de 2 x montant dans la direction y.
-padx => montant
- Un espace tampon, égal à montant, est placé à gauche et à droite du widget.
-pady => montant
- Un espace tampon, égal à montant, est placé au-dessus et en dessous du widget.
II-B-5. Désignation explicite des lignes et colonnes▲
Plutôt que de laisser grid faire des suppositions, il est parfois nécessaire de préciser explicitement la ligne et la colonne dans lesquelles placer le widget. Les options -row et -column sont faites pour ça. Chacune d'elles prend un entier positif comme paramètre :
-
column =>
n, -
row =>
m
Avec ces options, il n'est pas nécessaire de construire ou de placer les widgets dans un ordre logique quelconque (sauf pour votre propre confort lorsque vous rechercherez des erreurs). Vous pouvez placer votre premier widget en colonne 10 et ligne 5, si vous le désirez. Toutes les autres cellules se trouvant aux lignes et colonnes précédentes resteront vides.
II-B-6. Traverser explicitement des lignes et des colonnes▲
Il est également possible de préciser explicitement qu'un ou plusieurs widgets doivent traverser certaines colonnes ou lignes. Pour traverser des colonnes, on utilise l'option -columnspan et, pour traverser des lignes, l'option -rowspan. Toutes les deux prennent en paramètre un entier supérieur ou égal à 1. Cette valeur précise le nombre de lignes ou colonnes à traverser, elle comprend la ligne ou colonne dans laquelle le widget est placé.
Dans cet exemple, on utilise la façon simple de placer des widgets en ne spécifiant pas explicitement les options -row et -column. Remarquez que le second appel à grid s'applique aux deux widgets : en conséquence, l'option -columnspan s'applique aux deux boutons créés ici.
$mw-
>
Button(
-
text =>
"Bouton 1"
,
-
command =>
sub {
exit;
}
)->
grid(
$mw-
>
Button( -
text =>
"Bouton 2"
, -
command =>
sub {
exit }
),
$mw-
>
Button( -
text =>
"Bouton 3"
, -
command =>
sub {
exit }
),
$mw-
>
Button( -
text =>
"Bouton 4"
, -
command =>
sub {
exit }
),
-
sticky =>
"nsew"
);
# Bouton 5 occupera les colonnes 0-1, et Bouton 6 les colonnes 2-3
$mw-
>
Button(
-
text =>
"Bouton 5"
,
-
command =>
sub {
exit;
}
)->
grid(
$mw-
>
Button( -
text =>
"Bouton 6"
, -
command =>
sub {
exit }
),
-
sticky =>
"nsew"
,
-
columnspan =>
2
);
La fenêtre obtenue est celle de la figure 2.30.
Cette fenêtre pourrait aussi avoir été créée en utilisant le caractère spécial « - » afin d'indiquer l'extension de colonne de la façon suivante :
$mw-
>
Button(
-
text =>
"Bouton 1"
,
-
command =>
sub {
exit;
}
)->
grid(
$mw-
>
Button( -
text =>
"Bouton 2"
, -
command =>
sub {
exit }
),
$mw-
>
Button( -
text =>
"Bouton 3"
, -
command =>
sub {
exit }
),
$mw-
>
Button( -
text =>
"Bouton 4"
, -
command =>
sub {
exit }
),
-
sticky =>
"nsew"
);
# Bouton 5 occupera les colonnes 0-1, et Bouton 6 les colonnes 2-3
$mw-
>
Button( -
text =>
"Bouton 5"
, -
command =>
sub {
exit }
)
->
grid( "-"
, $mw-
>
Button( -
text =>
"Bouton 6"
, -
command =>
sub {
exit }
), "-"
, -
sticky =>
"nsew"
);
L'exemple suivant illustre l'utilisation explicite des options -row et -column en plus de l'option -rowspan :
$mw-
>
Button( -
text =>
"Bouton 1"
, -
command =>
sub {
exit }
)
->
grid( -
row =>
0
, -
column =>
0
, -
rowspan =>
2
, -
sticky =>
'nsew'
);
$mw-
>
Button( -
text =>
"Bouton 2"
, -
command =>
sub {
exit }
)
->
grid( -
row =>
0
, -
column =>
1
);
$mw-
>
Button( -
text =>
"Bouton 3"
, -
command =>
sub {
exit }
)
->
grid( -
row =>
0
, -
column =>
2
);
$mw-
>
Button( -
text =>
"Bouton 4"
, -
command =>
sub {
exit }
)
->
grid( -
row =>
0
, -
column =>
3
);
$mw-
>
Button( -
text =>
"Bouton 5"
, -
command =>
sub {
exit }
)
->
grid( -
row =>
1
, -
column =>
1
);
$mw-
>
Button( -
text =>
"Bouton 6"
, -
command =>
sub {
exit }
)
->
grid( -
row =>
1
, -
column =>
2
);
$mw-
>
Button( -
text =>
"Bouton 7"
, -
command =>
sub {
exit }
)
->
grid( -
row =>
1
, -
column =>
3
);
La fenêtre obtenue est celle de la figure 2.31.
II-B-7. Forcer un widget à remplir une cellule▲
Lorsque l'on utilise pack, il faut utiliser les deux options -fill et -expand pour que le widget change de taille dans son rectangle alloué. grid n'a pas de rectangle alloué à remplir mais une cellule dans la grille. L'utilisation de l'option -sticky avec grid est similaire à l'utilisation de -fill et -expand avec pack.
La valeur associée à -sticky est une chaîne contenant les points cardinaux sur lesquels doit se « coller » le widget. Si le widget doit toujours « coller » au sommet de la cellule, on utilise -
sticky =>
"n"
. Pour le forcer à remplir complètement la cellule, utilisez -
sticky =>
"nsew"
. Pour qu'il soit aussi haut que la cellule, mais de largeur normale, utilisez -
sticky =>
"ns"
. La chaîne peut contenir des virgules et des espaces, ils seront ignorés. Ces deux lignes sont donc équivalentes :
-
sticky =>
"nsew"
-
sticky =>
"n, s, e, w"
# Même chose
Si vous utilisez -sticky avec vos widgets, puis que vous modifiez la taille de la fenêtre, vous noterez que leur taille ne varie pas comme vous l'attendez. Cela est dû au fait que le changement de taille des cellules et des widgets qu'elles contiennent est pris en charge par les méthodes gridColumnconfigure et gridRowconfigure, étudiées plus loin dans ce chapitre.
II-B-8. Remplissage d'un widget▲
grid accepte aussi les quatre options suivantes : -ipadx, -ipady, -padx et -pady. Elles fonctionnent exactement comme avec pack mais, au lieu de modifier la taille du rectangle alloué, elles changent celle de la cellule dans laquelle se trouve le widget.
Dans l'exemple suivant, les options -ipadx et -ipady s'appliquent à la ligne de boutons supérieure, non à celle du bas. Remarquez comment les boutons 5 à 8 de la figure 2.32 sont aussi plus larges qu'ils ont réellement besoin de l'être. C'est parce que l'on utilise l'option -
sticky =>
"nsew"
.
$mw-
>
Button( -
text =>
"Bouton1"
, -
command =>
sub {
exit }
)->
grid(
$mw-
>
Button( -
text =>
"Bouton 2"
, -
command =>
sub {
exit }
),
$mw-
>
Button( -
text =>
"Bouton 3"
, -
command =>
sub {
exit }
),
$mw-
>
Button( -
text =>
"Bouton 4"
, -
command =>
sub {
exit }
),
-
sticky =>
"nsew"
,
-
ipadx =>
10
,
-
ipady =>
10
);
$mw-
>
Button( -
text =>
"Bouton 5"
, -
command =>
sub {
exit }
)->
grid(
$mw-
>
Button( -
text =>
"Bouton 6"
, -
command =>
sub {
exit }
),
$mw-
>
Button( -
text =>
"Bouton 7"
, -
command =>
sub {
exit }
),
$mw-
>
Button( -
text =>
"Bouton 8"
, -
command =>
sub {
exit }
),
-
sticky =>
"nse"
);
Dans l'exemple suivant, les options -padx et -ipady sont appliquées à la rangée supérieure de boutons, pas à celle du bas. Le résultat est donné par la figure 2.33.
$mw-
>
Button( -
text =>
"Bouton 1"
, -
command =>
sub {
exit }
)->
grid(
$mw-
>
Button( -
text =>
"Bouton 2"
, -
command =>
sub {
exit }
),
$mw-
>
Button( -
text =>
"Bouton 3"
, -
command =>
sub {
exit }
),
$mw-
>
Button( -
text =>
"Bouton 4"
,, -
command =>
sub {
exit }
),
-
sticky =>
"nsew"
,
-
padx =>
10
,
-
pady =>
10
);
$mw-
>
Button( -
text =>
"Bouton 5"
, -
command =>
sub {
exit }
)->
grid(
$mw-
>
Button( -
text =>
"Bouton 6"
, -
command =>
sub {
exit }
),
$mw-
>
Button( -
text =>
"Bouton 7"
, -
command =>
sub {
exit }
),
$mw-
>
Button( -
text =>
"Bouton 8"
, -
command =>
sub {
exit }
),
-
sticky =>
"nsew"
);
II-B-9. Utilisation d'un autre parent▲
L'option -in fonctionne comme avec pack. $widget
sera placé dans $autrefenetre
au lieu de l'être dans son parent par défaut. Voici comment utiliser cette option :
-
in =>
$autrefenetre
II-B-10. Configuration des colonnes et des lignes▲
Comme avec tous les gestionnaires d'espace, certaines méthodes sont associées à grid. Chacune d'elles est appelée via un widget placé sur l'écran à l'aide de grid. Il est parfois nécessaire de modifier les options du groupe de cellules formant notre grille.
On peut contrôler le changement de taille et la taille minimale d'une cellule avec les méthodes gridColumnconfigure et gridRowconfigure. Chacune d'elles prend un numéro de colonne ou de ligne comme premier paramètre et, éventuellement, d'autres paramètres modifiant la configuration de cette colonne ou ligne.
gridColumnconfigure et gridRowconfigure fonctionnent presque comme la méthode configure utilisée sur les widgets. À la différence de cette dernière, cependant, les options utilisables avec gridColumnconfigure et gridRowconfigure ne peuvent être utilisées avec la méthode grid. Les options possibles pour ces deux méthodes sont -weïght, -minsize et -pad.
Si vous ne passez qu'un numéro de ligne ou de colonne en paramètre, ces méthodes renvoient un tableau contenant les options courantes et leurs valeurs pour la méthode.
@config_co1onne
=
$mw-
>
gridColumnconfigure(0
);
@config_ligne
=
$mw-
>
gridRowconfigure(0
);
Dans l'exemple précédent, on récupère les valeurs des options de la première ligne et de la première colonne. Les résultats obtenus en utilisant les valeurs par défaut ressembleraient à ceci :
-
minsize 0
-
pad 0
-
weight 0
-
minsize 0
-
pad 0
-
weight 0
On peut récupérer la valeur d'une seule des options en précisant cette option en deuxième paramètre :
print
$mw-
>
gridColumnconfigure(0
, -
weight), "
\n
"
;
print
$mw-
>
gridRowconfigure(0
, -
weight), "
\n
"
;
Et les résultats seraient :
0
0
Pour changer la valeur d'une option, spécifiez-la avec la valeur que vous voulez lui associer ; par exemple :
$mw-
>
gridColumnconfigure( 0
, -
weight =>
1
);
$mw-
>
gridRowconfigure( 0
, -
weight =>
1
);
Vous pouvez également fournir plusieurs options dans le même appel :
$mw-
>
gridColumnconfigure( 0
, -
weight =>
1
, -
pad =>
10
);
$mw-
>
gridRowconfigure( 0
, -
weight =>
1
, -
pad =>
10
);
Maintenant que nous savons comment appeler gridColumnconfigure et gridRowconfigure, nous devons nous intéresser à ce que font les trois options de ces méthodes.
II-B-11. Poids d'une ligne ou d'une colonne▲
L'option -weight permet de préciser l'espace qui sera alloué à cette colonne ou à cette ligne lorsque la fenêtre est divisée en cellules. Rappelez-vous qu'il faut utiliser -
sticky =>
"nsew"
dans votre appel à grid si vous voulez que le widget change de taille en même temps que la cellule. La valeur par défaut de -weight. est 0, qui indique que la largeur de la colonne ou la hauteur de la ligne dépendront du widget le plus grand de la colonne ou de la ligne. Chaque valeur de -weight est en relation avec les autres -weight des lignes et colonnes.
Si une colonne ou une ligne a une option -weight valant 2, elle est deux fois de la taille d'une colonne ou d'une ligne ayant une valeur de 1 pour cette option. Les colonnes ou lignes ayant l'option -weight à 0 n'auront pas leur taille modifiée. Si vous voulez que tous vos widgets changent de taille en même temps que la fenêtre, ajoutez ceci à votre code avant d'appeler MainLoop :
( $colonnes
, $lignes
) =
$mw-
>
gridSize();
for ( $i
=
0
; $i
<
$colonnes
; $i
++
) {
$mw-
>
gridColumnconfigure( $i
, -
weight =>
1
);
}
for ( $i
=
0
; $i
<
$lignes
; $i
++
) {
$mw-
>
gridRowconfigure( $i
, -
weight =>
1
);
}
Ce code mettra un -weight de 1 pour chaque ligne et colonne de la grille, quelle que soit sa taille. Bien sûr, cette méthode ne fonctionne que si vous souhaitez mettre la même taille à toutes les lignes et à toutes les colonnes, mais cela vous donne une idée.
Voici un exemple du fonctionnement de l'option -weight (le résultat est donné par la figure 2.34) :
$mw-
>
Button( -
text =>
"Bouton 1"
, -
command =>
sub {
exit }
)->
grid(
$mw-
>
Button( -
text =>
"Bouton 2"
, -
command =>
sub {
exit }
),
$mw-
>
Button( -
text =>
"Bouton 3"
, -
command =>
sub {
exit }
),
$mw-
>
Button( -
text =>
"Bouton 4"
, -
command =>
sub {
exit }
),
-
sticky =>
"nsew"
);
$mw-
>
Button( -
text =>
"Bouton 5"
, -
command =>
sub {
exit }
)->
grid(
"x"
,
$mw-
>
Button( -
text =>
"Bouton 7"
, -
command =>
sub {
exit }
),
$mw-
>
Button( -
text =>
"Bouton 8"
, -
command =>
sub {
exit }
),
-
sticky =>
"nsew"
);
$mw-
>
gridColumnconfigure( 1
, -
weight =>
1
);
$mw-
>
gridRowconfigure( 1
, -
weight =>
1
);
En donnant à la ligne et à la colonne 1 un poids de 1, (alors que toutes les autres lignes et colonnes ont un poids de 0), celles-ci récupèrent tout l'espace supplémentaire rendu disponible par une augmentation de la taille de la fenêtre. Notez que les colonnes 0, 2 et 3 n'ont que la largeur suffisante pour afficher les boutons et leur texte, mais que la colonne 1 a rempli l'espace supplémentaire. Le même effet a lieu pour la ligne 0, qui a un poids de 0, et la ligne 1, qui a un poids de 1 (la fenêtre a été agrandie pour mettre en évidence les effets de -weight).
II-B-12. Taille minimale d'une cellule▲
L'option -minsize permet d'indiquer la largeur minimale d'une colonne ou la hauteur minimale d'une ligne. Sa valeur doit être une distance d'écran. Dans l'exemple qui suit,
la taille minimale des cellules de la ligne 0 et de celles de la colonne 0 est fixée à 10 pixels
$mw-
>
gridColumnconfigure(0
, -
minsize =>
10
);
$mw-
>
gridRowconfigure(0
, -
minsize =>
10
);
Si la colonne ou la ligne occupait théoriquement moins de 10 pixels, elle aura en fait au moins cette taille.
II-B-13. Remplissage▲
On peut ajouter des espaces de remplissage (padding) autour du widget, ainsi qu'au widget lui-même en utilisant les options -padx/y et -ipadx/y. Vous pouvez aussi en ajouter en utilisant l'option -pad avec les méthodes gridColumnconfigure et gridRowconfigure. Le remplissage est ajouté autour du widget, pas au widget lui-même. Lorsque vous appelez gridColumnconfigure, l'option -pad ajoutera des espaces à gauche et à droite du widget. L'appel de gridRowconfigure avec -pad ajoutera des espaces au-dessus et en dessous du widget. Voici deux exemples :
$mw-
>
gridColumnconfigure( 0
, -
pad =>
10
);
$mw-
>
gridRowconfigure( 0
, -
pad =>
10
);
II-B-14. Boîte de dimensionnement (Bounding box)▲
La méthode gridBbox permet de récupérer les dimensions d'une cellule :
($offset_x
, $offset_y
, $largeur
, $hauteur
) =
$cellule-
>
gridBbox(0
, 2
);
Cet exemple récupère la boîte de dimensionnement de la cellule située à la colonne 0, ligne 2. Toutes les valeurs renvoyées sont exprimées en pixels. La boîte de dimensionnement modifiera sa taille en même temps que celle de la fenêtre. Les quatre valeurs renvoyées représentent le décalage sur l'axe des x, le décalage sur l'axe des y, la largeur de la cellule et sa hauteur (les décalages sont relatifs à la fenêtre ou au cadre dans lequel le widget est placé).
II-B-15. Suppression d'un widget▲
Tout comme packForget, gridForget met le(s) widget(s) hors de vue. Cela peut, ou ne pas, forcer la fenêtre à changer de taille ; cela dépend de la taille du widget et de l'endroit où il se trouvait dans la fenêtre. Voici quelques exemples :
$mw-
>
gridForget(); # Rien ne se passe
$widget-
>
gridForget(); # $widget disparaît
$widget-
>
gridForget($widget1
); # $widget et $widget1 disparaissent
$widget-
>
gridForget( $w1
, $w3
); # $widget, $w1 et $w3 disparaissent
Les widgets disparaissent de la fenêtre, mais les cellules qu'ils occupaient continuent d'exister.
II-B-16. Obtenir des informations▲
La méthode gridlnfo renvoie des informations sur $widget
sous la forme d'une liste. Tout comme packInfo, les deux premiers éléments indiquent où a été placé le widget :
@liste
=
$widget-
>
gridlnfo();
Voici un exemple de résultats produits par gridInfo :
-in Tk::Frame=HASH(0x81abc44) -column 0 -row 0 -columnspan 1
-rowspan 2 -ipadx 0 -ipady 0 -padx 0 -pady 0 -sticky nesw
II-B-17. Emplacement d'un widget▲
La méthode gridLocation renvoie la colonne et la ligne du widget le plus près des coordonnées (x, y) spécifiées :
($colonne
, $ligne
) =
$mw-
>
gridLocation($x
, $y
)
$x
et $y
sont exprimés en unités d'écran relatives à la fenêtre maître ($mw
, dans nos exemples). La valeur -1 est renvoyée pour les emplacements au-dessous ou à gauche de la grille.
Lorsqu'on lui passe les paramètres (0, 0), gridLocation retourne : 0 0 qui indique la cellule en colonne 0 et ligne 0.
II-B-18. Propagation▲
Il existe une méthode gridPropagate qui ressemble à packPropagate :
$mw-
>
gridPropagate( 0
);
Lorsqu'on lui passe une valeur fausse, gridPropagate désactive la propagation d'espace, ce qui signifie que les informations de taille ne sont pas remontées au parent de $mw
. Par défaut, la propagation est activée. Sans paramètre, gridPropagate renvoie sa valeur courante.
II-B-19. Combien de colonnes et de lignes ?▲
Pour savoir la taille que la grille a atteinte après y avoir placé de nombreux widgets, on peut utiliser la méthode gridSize qui renvoie le nombre de colonnes et de lignes de la grille :
($colonnes
, $lignes
) =
$mw-
>
gridSize();
La liste obtenue contient le nombre de colonnes puis de lignes. Dans beaucoup des exemples précédents, nous avions une taille de grille de 4 colonnes par 2 lignes.
($colonnes
, $lignes
) =
$fenetre-
>
gridSize();
Il n'est pas nécessaire qu'un widget soit placé dans une colonne/ligne pour que cette paire soit considérée comme une combinaison colonne/ligne correcte. Si l'on place un widget en colonne 4 et ligne 5 en utilisant -
row =>
5
, -
column =>
4
et que le seul autre widget se trouve en colonne 0 et ligne 0, gridSize renverra 5 et 6.
II-B-20. Énumération des widgets▲
Il y a deux moyens de trouver quels sont les widgets qui ont été placés avec grid dans une fenêtre ou dans un cadre. On utilise gridSlaves sans paramètre pour obtenir une liste complète ou bien l'on donne une ligne et une colonne. Voici des exemples de ces deux façons de faire :
@esclaves
=
$mw-
>
gridSlaves();
print
"
@esclaves\n
"
;
Ce code afficherait quelque chose comme :
Tk::Button=HASH(0x81b6fb8) Tk::Button=HASH(0x81ba454)
Tk::Button=HASH(0x81ba4cc) Tk::Button=HASH(0x81ba538)
Tk::Button=HASH(0x81ba6dc) Tk::Button=HASH(0x81ba748)
Nous aurions pu spécifier le widget de la colonne 0, ligne 0 :
$widget
=
$mw-
>
gridSlaves( -
row =>
0
, -
column =>
0
);
print
"
$widget\n
"
;
# Cela afficherait : Tk::Button=HASH(0x81b6fb8)
Si l'on ne précise que l'option -row, on obtient une liste ne contenant que les widgets de cette ligne. La même chose se passe si l'on ne spécifie que l'option -column : la liste ne contiendra que les widgets de cette colonne.
II-C. Place▲
Le gestionnaire d'espace place diffère de grid et de pack. Au lieu de prendre comme référence un emplacement de cellule ou le bord d'une fenêtre, vous utiliserez la plupart du temps des coordonnées x et y relatives. Vous pouvez aussi utiliser place pour faire se chevaucher des parties de widgets, ce qui est impossible avec grid et pack.
L'appel de place ressemble à celui des autres gestionnaires d'espace :
$widget-
>
place( [ option =>
valeur, . . . ] );
Les options spécifiées lors de l'appel de place affectent la façon dont sont placés les widgets à l'écran.
II-C-1. 0ptions de place▲
-anchor => 'n' | 'ne' | 'e' | 'se' 1 's' | 'sw' | 'w' | 'nw' | 'center'
- Configure la position dans le widget qui sera placée aux coordonnées précisées.
-bordermode => 'inside' | 'outside' | 'ignore'
- Détermine si la partie frontière du widget sera incluse ou non dans le système de coordonnées.
-height => montant
- Configure la hauteur absolue du widget.
-in => $fenetre
- Indique que le widget fils sera placé dans
$fenetre
au lieu du parent qui l'a créé. Toutes les coordonnées ou tailles relatives font quand même référence au parent.
-relheight => ratio
- Indique que la hauteur du widget a un rapport de ratio avec celle du widget parent.
-relwidth => ratio
- Indique que la largeur du widget a un rapport de ratio avec celle du widget parent.
-relx => xratio
- Indique que le widget sera déplacé de xratio, relativement à son widget parent.
-rely => yratio
- Indique que le widget sera déplacé de yratio, relativement à son widget parent.
-width => montant
- Indique que la largeur du widget sera de montant.
-x => x
- Indique que le widget sera placé en z. z est une distance d'écran.
-y => y
- Indique que le widget sera placé en y. y est une distance d'écran.
II-C-2. Coordonnées absolues▲
La fenêtre (ou le cadre) parent a un système de coordonnées standard où 0,0 représente le coin supérieur gauche. Les valeurs x augmentent vers la droite, tandis que les valeurs y augmentent vers le bas. C'est représenté par la figure 2.35.
On utilise les options -x et -y pour utiliser des coordonnées absolues afin de préciser l'emplacement du widget :
-x
=>
x
, -
y =>
y
Les valeurs acceptées pour x et y sont des distances d'écran (par exemple, 5, qui est exprimé en pixels). Ces coordonnées seront celles du point d'ancrage (contrôlé par -anchor) du widget. L'ancrage par défaut est "nw", le coin supérieur gauche du widget.
Une autre différence majeure entre place et les autres gestionnaires d'espace est que l'appel de place nécessite au moins deux paramètres. Il n'y a pas de valeurs par défaut pour les options -x et -y et vous obtiendrez une erreur si vous essayez d'appeler place sans paramètre (en faisant, par exemple, $widget-
>
place()).
L'exemple le plus simple de l'utilisation de -x et -y consiste à placer un widget aux coordonnées 0,0 :
Comme l'on pourrait s'y attendre, le widget se place dans le coin supérieur gauche de la fenêtre, ainsi que le montre la figure 2.36. Peu importe la taille de la fenêtre : notre widget restera positionné en 0,0. Même lorsque la fenêtre prend la plus petite taille possible, le widget ne bouge pas.
Voici un exemple d'utilisation de -x et -y pour créer des widgets qui se chevauchent (figure 2.37)
II-C-3. Coordonnées relatives▲
Avec place, il existe un autre système de coordonnées, défini pour le widget parent, et qui permet un placement relatif dans celui-ci. Ce système de coordonnées est montré par la figure 2.38.
Le coin supérieur gauche a les coordonnées (0.0, 0.0) et le coin inférieur droit, les coordonnées (1.0, 1.0). Le centre de la fenêtre serait donc (0.5, 0.5). Ces coordonnées sont exprimées sous une forme en virgule flottante afin de permettre à place de gérer n'importe quelle taille de fenêtre. Cela permet au widget de rester à sa position (au centre, par exemple), quels que soient les changements de taille de la fenêtre.
Il est permis de spécifier des coordonnées inférieures à 0.0 ou supérieures à 1.0. Cependant, il y a fort à parier que le widget ne sera pas complètement visible dans la fenêtre si vous utilisez des coordonnées en dehors de cet intervalle.
Le code suivant produit le bouton montré à la figure 2.39 :
$bouton
=
$mw-
>
Button(-
text =>
"Fin"
, -
command =>
sub {
exit }
);
$bouton-
>
place(-
relx =>
0
.5
, -
rely =>
0
.5
);
Bien que le bouton de la figure 2.39 soit placé au centre de la fenêtre, il semble en être décalé car c'est le coin supérieur gauche du widget, et non son centre, qui a été placé au milieu de la fenêtre. On peut changer ceci en utilisant -anchor, dont je parlerai dans un instant. Si nous changeons la taille de cette fenêtre, le bouton reste quand même au milieu (voir la figure 2.40).
L'exemple suivant crée deux boutons, placés dans la fenêtre à l'aide de coordonnées relatives.
$mw-
>
Button(
-
text =>
"Fin"
,
-
command =>
sub {
exit }
)->
place(
-
relx =>
0
.2
,
-
rely =>
0
.2
);
$mw-
>
Button(
-
text =>
"Fin"
,
-
command =>
sub {
exit }
)->
place( -
relx >
0
.5
, -
rely =>
0
.5
);
Quelle que soit la taille de la fenêtre ou l'emplacement des autres widgets, les deux boutons resteront à ces coordonnées relatives (voir la figure 2.41).
La fenêtre gauche de la figure 2.41 a la taille qui lui a été donnée lors de sa création. Celle de droite est cette même fenêtre dont on a modifié la taille pour qu'elle soit bien plus petite. Notez que le second bouton reste au-dessus. C'est parce que l'ordre de la liste des widgets de la fenêtre est conservé ; le second bouton « Fin » (placé en 0.5, 0.5) est dessiné en dernier, il est donc tracé au-dessus de l'autre bouton.
On peut aussi combiner les systèmes de coordonnées absolues et de coordonnées relatives en utilisant les deux dans la liste des paramètres. Le système de coordonnées relatives est le premier pris en compte, puis les valeurs des options -x et -y sont ajoutées à cette position. Les options -
relx =>
0
.5
, -x
=>
-
10
indiquent de placer le widget 10 pixels à gauche du centre de la fenêtre.
II-C-4. Ancrage d'un widget▲
Pensez au widget fils comme à un morceau de papier que vous voudriez mettre sur un tableau de liège (le tableau est le widget parent). Vous utiliseriez une punaise pour maintenir le papier sur le tableau. Vous pouvez placer cette punaise au centre du papier, dans son coin supérieur gauche (« nw »), ou dans le coin inférieur droit (« se »). Le point où la punaise maintiendra le papier au tableau est le point d'ancrage. Le point spécifié par -anchor est « punaisé » aux coordonnées données par -x et -y, ou par -relx, -rely. La valeur par défaut d'-anchor est « nw ». La figure 2.38 montre ces points d'ancrage dans le widget fils.
Il est important de savoir où est le point d'ancrage car cela affectera la présentation du widget dans son parent.
Des instructions de placement quasiment identiques ont été utilisées pour placer le bouton « Fin » dans les fenêtres de la figure 2.42. La différence réside en la modification de l'option -anchor. Le bouton de la fenêtre de gauche a été créé ainsi :
$mw-
>
Button(
-
text =>
"Fin"
,
-
command =>
sub {
exit }
)->
place(
-
relx =>
0
.5
,
-
rely =>
0
.5
);
La fenêtre de droite a utilisé le placement suivant :
$mw-
>
Button(
-
text =>
"Fin"
,
-
command =>
sub {
exit }
)->
place(
-
relx =>
0
.5
,
-
anchor =>
"center"
,
-
rely =>
0
.5
);
Comme avec pack et grid, les valeurs possibles de -anchor sont : 'n', 'e', 's', 'w', 'center', 'nw', 'sw', 'ne' et 'se'. Cependant, la valeur s'applique maintenant au widget fils plutôt qu'à la position dans le rectangle alloué.
II-C-5. Largeur et hauteur▲
Lorsque l'on utilise place, on peut indiquer la largeur et la hauteur du widget en utilisant l'une de ces trois possibilités :
- autoriser le widget à déterminer sa propre taille ;
- préciser la largeur et/ou la hauteur en mesures absolues ;
- préciser la largeur et/ou la hauteur en mesures relatives (au widget parent).
Pour laisser les widgets déterminer leur propre taille, on ne spécifie aucune option. Les autres solutions impliquent d'utiliser les options -width, -height et -relwidth, -relheight, respectivement.
Les options -width et -height permettent d'indiquer la largeur et la hauteur exactes du widget, exprimées en distances d'écran :
-
width =>
montant, -
height =>
montant
Chaque montant est une distance d'écran (ce terme a été introduit plus haut, avec pack). Le widget gardera ces tailles, même s'il coupe les bords des éléments qu'il contient. Notre bouton apparaît plutôt bizarrement sur l'écran lorsque l'on utilise une largeur de 40 pixels (voir la figure 2.43).
$mw-
>
Button(
-
text =>
"Ce bouton provoquera la fin du programme"
,
-
command =>
sub {
exit }
)->
place(
-x
=>
0
,
-
y =>
0
,
-
width =>
40
);
Les deux autres options, -relwidth et -relheight, déterminent la largeur et la hauteur du widget par rapport à celles du widget parent.
-
relwidth =>
ratio, -
relheight =>
ratio
ratio est un nombre en virgule flottante (comme les valeurs utilisées par -relx ou -rely). Une valeur de 1.0 rendra le widget aussi large (ou aussi haut) que son parent. Une valeur de 0.5 le réduira de moitié par rapport à son parent (voir la figure 2.44).
Lorsqu'elles sont utilisées ensemble, les options -width et -relwidth s'ajoutent, c'est aussi le cas de -height et -relheight.
II-C-6. Options de prise en compte des contours ▲
NorSmalement, le contour du widget est utilisé comme frontière de l'espace possible dans la fenêtre, ce qui signifie que tout widget placé avec les systèmes de coordonnées absolues ou relatives sera placé à l'intérieur de ce contour. Ce comportement peut être modifié en utilisant l'option -bordermode.
- -bordermode => 'inside' | 'outside' | 'ignore'
L'utilisation de 'outside' permettra au système de coordonnées d'utiliser aussi l'espace occupé par le contour. 'ignore' fera que le système de coordonnées utilisera la zone X Window officielle. Cependant, cette option est peu utile, ainsi que vous pouvez vous en rendre compte en visualisant les différences induites par ces trois valeurs dans l'exemple de la figure 2.45.
Si l'on y regarde de très près (prenez votre loupe), on peut constater que la version utilisant "outside" est plus haute et plus large de deux pixels que la version utilisant "inside". Cela est dû à mon gestionnaire de fenêtre (fvwm) : mes contours ont une largeur de deux pixels.
II-C-7. Méthodes associées à place ▲
Les méthodes associées à place sont simples et ne permettent pas de beaucoup manipuler les widgets.
II-C-7-a. Suppression d'un widget ▲
Comme pack et grid, place dispose d'une méthode permettant de supprimer un widget.
$widget-
>
placeForget();
Si l'on utilise cette méthode sur un widget, celui-ci sera supprimé de l'écran. Il sera aussi ôté de la liste gérée par le widget parent.
II-C-7-b. Informations sur les emplacements ▲
La méthode placeInfo renvoie une liste d'informations sur le widget :
@infos
=
$widget-
>
placeInfo();
print
"
@infos
"
;
## Résultats produits (il y a des espaces aux endroits sans valeur)
-x
0
-
relx 0
-
y 0
-
rely 0
-
width -
relwidth -
height -
relheight -
anchor nw
II-C-7-c. Énumération des widgets ▲
@widgets
=
$parent-
>
placeSlaves();
La méthode placeSlaves renvoie une liste des widgets fils contenus dans $parent
. Cette liste ressemble à celle que produisent les méthodes packSlaves et gridSlaves.
II-D. Résumé sur la gestion de l'espace ▲
Vous en savez maintenant plus sur les trois différents gestionnaires d'espace que vous n'aurez jamais besoin d'en savoir pour écrire des applications Perl/Tk correctes. Voici quelques conseils pratiques pour décider du gestionnaire à utiliser :
- pack convient bien à une utilisation générale, et vous le choisirez dans 95 % des cas ;
- grid est parfait lorsque vous souhaitez créer une disposition en colonnes identique à celle d'une feuille de calcul d'un tableur ;
- place est le plus utile lorsque vous souhaitez que vos widgets conservent une position ou une taille relatives au widget qui les a créés. Utilisé correctement, il est très puissant ;
- quel que soit le gestionnaire utilisé, prenez votre temps afin d'avoir des widgets sur la fenêtre à laquelle ils appartiennent (ou, plus probablement, à l'endroit où vous le souhaitez). Il n'y a rien de plus déconcertant qu'un bouton semblant ne pas appartenir à la bonne fenêtre.
Au fur et à mesure de la lecture de ce livre, vous noterez que certains noms d'options des gestionnaires d'espace sont aussi des noms d'options utilisés pour créer ou configurer un type de widget. On peut, par exemple, spécifier l'option -width d'un bouton sans utiliser place. Rappelez-vous toujours le contexte dans lequel l'option est utilisée : la différence de fonctionnement est parfois très subtile.