Object +-- Widget +-- Container +-- Box
En créant une application, vous voudrez mettre plus d'un widget à l'intérieur
d'un fenêtre. Notre premier exemple utilisait seulement un widget ainsi nous
avons pu simplement utiliser un appel $window->add() pour placer le widget
dans la fenêtre. Mais quand on place plus d'un widget dans la fenêtre, comment
contrôlez-vous l'endroit où est placé le widget ? C'est là que les boîtes de
regroupement interviennent.
Le rangement est fait en créant des boîtes puis en regroupant les widgets à l'intérieur. Ces boîtes sont des conteneurs invisibles dans lesquelles on peut regrouper les widgets. Elles sont de deux formes : une boite horizontale et une boîte verticale. En rangeant les widgets dans une boîte horizontale, les objets sont insérés de la gauche vers la droite ou de la droite vers la gauche en fonction de l'appel utilisé. Pour une boîte verticale, le rangement se fait de bas en haut ou vice-versa. Vous pouvez utiliser des combinaisons en rangeant des boîtes à l'intérieur d'autres boîtes, ou à côté afin de produire l'effet désiré.
Pour créer une nouvelle boîte horizontale ou verticale :
$box = new Gtk::HBox( $homogeneous, $spacing ); $box = new Gtk::VBox( $homogeneous, $spacing );
Si $homogeneous est une valeur vraie alors tous les widgets rangés à
l'intérieur disposeront du même espace. $spacing est la taille en pixels
entre chaque ``marque'' disponible pour les widgets.
Les fonctions suivantes sont utilisées pour placer les objets dans les boîtes :
$box->pack_start( $child, $expand, $fill, $padding ); $box->pack_end( $child, $expand, $fill, $padding );
La fonction pack_start() commencera en haut d'une VBox et continuera
vers le bas et range de la gauche vers la droite dans une HBox. pack_end()
fera le contraire. Ces fonctions nous permettent juste de justifier à droite
ou à gauche la position des widgets et peuvent être mélangées pour obtenir l'effet
désiré. L'objet ajouté peut-être ou bien un conteneur ou bien un widget. En
fait, de nombreux widgets sont eux-même des conteneurs ( les boutons par exemple,
mais nous n'utilisons en général qu'un label ou un icône à l'intérieur des boutons
).
Comme vous l'avez peut-être deviné, l'argument $child est le widget
à placer dans la boîte. Si l'argument $expand est une valeur vraie alors
les widgets seront disposés dans la boîte pour remplir l'espace qui leurs est
alloué. Déclarer $expand comme valeur fausse vous permettra de faire
des justifications à droite et à gauche de vos widgets. Noter que déclarer $expand
vraie pour une boîte revient à déclarer $expand vraie pour chaque widget.
Si l'argument $fill est une valeur vraie alors tout espace vide est
alloué aux objets eux-même. Autrement l'espace vide est un emballage dans la
boîte autour des objets. Cela a de l'effet uniquement si l'argument $expand
est vrai.
En utilisant ces appels, GTK sait ou vous voulez placer vos widgets et peut ainsi redimensionner ou faire d'autres choses sympathiques. Comme vous l'imaginez, cette méthode nous donne une certaine flexibilité quand on crée et place des widgets.
En raison de cette flexibilité, le rangement dans les boîtes peut être déroutant au début. Il y a beaucoup d'options et il n'est pas immédiatement évident de les arranger entre elles. En fait, il y a cinq styles de base différents. Ces cinq styles sont illustrés ci-dessous.
Chaque ligne de l'exemple contient une boîte horizontale avec plusieurs boutons.
L'appel pour ranger est un raccourci pour regrouper chaque bouton dans une boîte.
Chaque bouton est placé dans la boîte de la même manière ( les arguments sont
passées à la fonction pack_start() ). C'est une forme raccourcie de
pack_start() et de pack_end() qui déclare $expand vraie,
$fill vraie et $padding 0.
Ces fonctions sont :
$box->pack_start_defaults( $widget ); $box->pack_end_defaults( $widget );
La valeur homogeneous de la boîte peut être allumée ou éteinte en utilisant
la fonction :
$box->set_homogeneous( $homogeneous );
De même pour la valeur spacing :
$box->set_spacing( $spacing );
Si vous voulez déplacer un enfant, utilisez :
$box->reorder_child( $child, $position );
$child est le widget à déplacer et $position est la position à
changer en partant de 0. Si vous voulez connaître l'ordre actuel, regardez la
liste fournie par l'appel à la fonction sur les conteneurs children().
Si vous voulez changer un regroupement d'enfants, vous pouvez utiliser :
$box>set_child_packing( $widget, $expand, $fill, $padding, $pack_type );
Les arguments sont les mêmes que pour les fonctions pack_start() et pack_end()
à l'exception de $pack_type qui est soit 'start' soit 'end'.
Quelle est la différence entre l'espace ( spacing ), déclaré quand la boîte est créée, et l'emballage ( padding ), déclaré quand les éléments sont rangés ? L'espace est ajouté entre les objets et l'emballage est ajouté de chaque côté de l'objet.
Voici le code utilisé pour créer la fenêtre illustrée ci-dessous. Je l'ai abondamment commenté ainsi j'espère que vous n'aurez aucun problème à le comprendre, mais soyez conscient qu'il est assez long. Faîtes le tourner par vous-même et jouer avec.
#!/usr/bin/perl -wuse Gtk;
use strict;
init Gtk;
unless ( $ARGV[0] ) { print( "usage: packbox num, where num is 1, 2, or 3.\n" ); Gtk->exit( 1 ); exit( 1 ); }
my $false = 0;
my $true = 1;
my $which = $ARGV[0];
my $window;
my $box1;
my $box2;
my $label;
my $separator;
my $quitbox;
my $button;
# Vous devriez toujours vous souvenir de connecter le signal delete_event
# à la fenêtre principale. C'est très important pour obtenir un comportement
# intuitif propre.
$window = new Gtk::Window( "toplevel" );
$window->signal_connect( "delete_event", sub { Gtk->exit( 0 ); } );
$window->border_width( 10 );
# Nous créons une boîte verticale ( vbox ) pour regrouper les boîtes
# horizontales. Cela permet d'y placer les boîtes horizontales remplies
# de boutons les unes au-dessus des autres.
$box1 = new Gtk::VBox( $false, 0 );
# quel exemple montrer. Celui-là correspond à la figure ci-dessus.
if ( $which == 1 ) { # crée un nouveau label. $label = new Gtk::Label( 'new Gtk::HBox( $false, 0 );' ); # Aligne le label sur le côté gauche. Nous discuterons de cette # fonction et des autres dans la section sur les Attributs # d'un widget. $label->set_alignment( 0, 0 ); # Place le label dans la boîte verticale (vbox box1). Souvenez vous # que les widgets sont ajoutés dans la vbox les uns au-dessus # autres. $box1->pack_start( $label, $false, $false, 0 ); # montre le label $label->show(); # Appelle notre fonction fabricante de boîte- homogeneous = FALSE, # spacing = 0, expand = FALSE, fill = FALSE, padding = 0 $box2 = make_box( $false, 0, $false, $false, 0 ); $box1->pack_start( $box2, $false, $false, 0 ); $box2->show(); # Appelle notre fonction fabricante de boîte- homogeneous = FALSE, # spacing = 0, expand = TRUE, fill = FALSE, padding = 0 $box2 = make_box( $false, 0, $true, $false, 0 ); $box1->pack_start( $box2, $false, $false, 0 ); $box2->show(); # Les arguments sont : homogeneous, spacing, expand, fill, padding $box2 = make_box( $false, 0, $true, $true, 0 ); $box1->pack_start( $box2, $false, $false, 0 ); $box2->show(); # Crée un séparateur, nous les verrons plus tard, mais # ils sont plutôt simples. $separator = new Gtk::HSeparator(); # Place le séparateur dans la vbox. $box1->pack_start( $separator, $false, $true, 5 ); $separator->show(); # Crée un nouveau label et le montre. $label = new Gtk::Label( 'new Gtk::HBox( $true, 0 );' ); $label->set_alignment( 0, 0 ); $box1->pack_start( $label, $false, $false, 0 ); $label->show(); # Les arguments sont : homogeneous, spacing, expand, fill, padding $box2 = make_box( $true, 0, $true, $false, 0 ); $box1->pack_start( $box2, $false, $false, 0 ); $box2->show(); # Les arguments sont: homogeneous, spacing, expand, fill, padding $box2 = make_box( $true, 0, $true, $true, 0 ); $box1->pack_start( $box2, $false, $false, 0 ); $box2->show(); # Un autre nouveau séparateur. $separator = new Gtk::HSeparator(); # Les 3 derniers arguments de gtk_box_pack_start sont: # expand, fill, padding. $box1->pack_start( $separator, $false, $true, 5 ); $separator->show(); }
elsif ( $which == 2 ) { # Crée un nouveau label, souvenez vous que box1 est une vbox # créée près du début de main() $label = new Gtk::Label( 'new Gtk::HBox( $false, 10 );' ); $label->set_alignment( 0, 0 ); $box1->pack_start( $label, $false, $false, 0 ); $label->show(); # Les arguments sont : homogeneous, spacing, expand, fill, padding $box2 = make_box( $false, 10, $true, $false, 0 ); $box1->pack_start( $box2, $false, $false, 0 ); $box2->show(); # Les arguments sont: homogeneous, spacing, expand, fill, padding $box2 = make_box( $false, 10, $true, $true, 0 ); $box1->pack_start( $box2, $false, $false, 0 ); $box2->show(); $separator = new Gtk::HSeparator(); #Les 3 derniers arguments de gtk_box_pack_start sont : expand, fill, # and padding. $box1->pack_start( $separator, $false, $true, 5 ); $separator->show(); $label = new Gtk::Label( 'new Gtk::HBox( $false, 0 );' ); $label->set_alignment( 0, 0 ); $box1->pack_start( $label, $false, $false, 0 ); $label->show(); # Les arguments sont: homogeneous, spacing, expand, fill, padding $box2 = make_box( $false, 0, $true, $false, 10 ); $box1->pack_start( $box2, $false, $false, 0 ); $box2->show(); # Les arguments sont: homogeneous, spacing, expand, fill, padding $box2 = make_box( $false, 0, $true, $true, 10 ); $box1->pack_start( $box2, $false, $false, 0 ); $box2->show(); $separator = new Gtk::HSeparator(); #Les 3 derniers arguments de pack_start sont: expand, fill, # and padding. $box1->pack_start( $separator, $false, $true, 5); $separator->show(); }
elsif ( $which == 3 ) { # Cela montre la possibilité d'utiliser pack_end() pour justifier # les widgets sur la droite. Premièrement, nous créons une # nouvelle boîte comme précédemment. $box2 = make_box( $false, 0, $false, $false, 0); # Crée un nouveau label qui sera placé à la fin. $label = new Gtk::Label( "end" ); # Le place à l'aide de gtk_box_pack_end(), ainsi il est mis # sur la droite de la hbox créée par l'appel make_box(). $box2->pack_end( $label, $false, $false, 0 ); # Montre le label. $label->show(); # Place la box2 dans la box1 (la vbox, vous vous souvenez ? :) $box1->pack_start( $box2, $false, $false, 0 ); $box2->show(); # Un séparateur pour le fond. $separator = new Gtk::HSeparator(); # Cela déclare explicitement le widget de 400 pixels de large # sur 5 pixels de haut. C'est ainsi que la hbox que nous avons # créée sera également de 400 pixels de large, et le label de # ``fin'' sera séparé des autres labels dans la hbox. Autrement # les widgets seraient placés dans la hbox le plus près possible # les uns des autres. $separator->set_usize( 400, 5 ); # place le séparateur dans la vbox (box1) créée près du # début du programme. $box1->pack_start( $separator, $false, $true, 5 ); $separator->show(); }
# Crée une autre nouvelle hbox. Souvenez vous que l'on peut
# en utiliser autant l'on en veut.
$quitbox = new Gtk::HBox( $false, 0 );
# Notre bouton quit.
$button = new Gtk::Button( "Quit" );
# Enregistre le signal qui ferme le programme quand le
# bouton est cliqué.
$button->signal_connect( "clicked", sub { Gtk->exit( 0 ); } );
# Place le bouton dans la quitbox.
# Les 3 derniers arguments de gtk_box_pack_start sont :
# expand, fill, padding.
$quitbox->pack_start( $button, $true, $false, 0 );
# place la quitbox dans la vbox (box1)
$box1->pack_start( $quitbox, $false, $false, 0 );
# Place la vbox (box1) qui contient tous nos widgets,
# dans la fenêtre principale.
$window->add( $box1 );
# Montre tout ce qui reste
$button->show();
$quitbox->show();
$box1->show();
# Montrer la fenêtre en dernier pour que tout apparaisse d'un coup.
$window->show();
# Et bien sûr notre fonction main.
main Gtk;
exit( 0 );
### Routines
# Crée une nouvelle boîte hbox avec des boutons labels. Les arguments
# pour les variables qui nous intéressent sont passés à la fonction.
# Nous ne montrons pas la boîte, mais montrons tout ce qui est
# à l'intérieur.
sub make_box { my ( $homogeneous, $spacing, $expand, $fill, $padding ) = @_; # Crée une nouvelle hbox avec les valeurs homogeneous # et spacing appropriées. my $box = new Gtk::HBox( $homogeneous, $spacing ); $button = new Gtk::Button( '$box->' ); $box->pack_start( $button, $expand, $fill, $padding ); $button->show(); # Crée une série de boutons avec les valeurs appropriées. $button = new Gtk::Button( "pack" ); $box->pack_start( $button, $expand, $fill, $padding ); $button->show(); $button = new Gtk::Button( '( $button,' ); $box->pack_start( $button, $expand, $fill, $padding ); $button->show(); # Crée un bouton dépendant de la valeur de expand. if ( $expand ) { $button = new Gtk::Button( '$true,' ); } else { $button = new Gtk::Button( '$false,' ); } $box->pack_start( $button, $expand, $fill, $padding ); $button->show(); # C'est la même chose que la création du bouton pour ``expand''. if ( $fill ) { $button = new Gtk::Button( '$true,' ); } else { $button = new Gtk::Button( '$false,' ); } $box->pack_start( $button, $expand, $fill, $padding ); $button->show(); $button = new Gtk::Button( "$padding );" ); $box->pack_start( $button, $expand, $fill, $padding ); $button->show(); return ( $box ); }