Chapitre 6
Les boutons

Les boutons normaux

Créer un bouton

Les fonctions suivantes créent un bouton :

$button = Gtk2::Button->new();  
$button = Gtk2::Button->new( $label );  
$button = Gtk2::Button->new_with_label ( $label );  
$button = Gtk2::Button->new_with_mnemonic( $label );  
$button = Gtk2::Button->new_from_stock( $id );  

La première des fonctions ci-dessus crée un bouton vide. Les deux suivantes créent un bouton avec un label. La seconde est en fait une forme raccourcie de la troisième. Si vous créez un bouton avec un label, vous pouvez utiliser  $button->child pour accéder au widget enfant. Par exemple, pour changer le texte d’un label, vous pourrez utiliser :

$button->child->set( "new label" );

La quatrième fonction ajoute à cela une nouvelle fonctionnalité. Elle permet, en plus d’afficher un label, de faire réagir le bouton à l’aide d’un raccourci clavier. La touche servant de raccourci est spécifiée dans le paramètre label. Il suffit de mettre “_” devant la lettre souhaitée pour que la combinaison Alt +Touche active le bouton. Par exemple pour l’application de ce chapitre, le texte à afficher sera “Quitter” et si nous voulons que la combinaison de touches Alt + Q permette de quitter l’application, le paramètre label devra être “_Quitter”.

La cinquième fonction permet de créer un bouton avec un label, un raccourci clavier et une image. Cependant, pour faire cela, GTK+ utilise les GtkStockItem qui est une structure contenant les informations sur le label et l’image à afficher. GTK+ comporte déjà beaucoup de GtkStockItem prédéfinis (en tout cas les plus courant). Le paramètre $id est donc une chaîne identifiant le GtkStockItem à utiliser. Pour notre exemple, l’identifiant est 'gtk-close'.

Les signaux des boutons

Les boutons possèdent les signaux suivants :

Styles de relief

Les styles de relief des boutons peuvent être :  'normal' ,  'half'  ,  'none' . Il est évident que le style par défaut est :  'normal' . Pour obtenir ou déclarer le style de relief, vous devrez utiliser les fonctions suivantes ;

$button->set_relief($relief_style );  
$button->get_relief();

Exemple

Dans le programme suivant, je crée d’abord un bouton avec label auquel j’attache un gestionnaire de signal. à chaque fois que l’on clique sur le bouton, celui-ci est détruit et remplacé par un autre. Le but est de vous montrer les différentes possibilités.

bouton11 bouton12 bouton13 bouton14

# !/usr/bin/perl -w

use Gtk2 ’-init’ ;

use constant TRUE => 1 ;
use constant FALSE => 0 ;

# Nombre de click sur le bouton
my $numclicked = 0 ;

# Création de la fenêtre
my $window = Gtk2::Window->new( ”toplevel” ) ;
$window->signal_connect( ”delete_event” , sub {Gtk2->main_quit ;}) ;
$window->set_border_width( 15 ) ;

# Création du bouton avec un texte qui est en réalité
# un label anonyme.
my $button = Gtk2::Button->new( ”Texte initial” ) ;
$button->signal_connect( ”clicked” , \&ClickedButtonEvent ) ;
$window->add( $button ) ;
$button->show() ;

# montre la fenêtre
$window->show() ;

# boucle d’évènement Gtk2
Gtk2->main ;


### Routines
# fonction appelée quand le bouton est clické

sub ClickedButtonEvent
{
if ( $numclicked == 0 )
{
# Pour avoir accès au label contenu dans le bouton,
# on doit appeler la méthode child héritée de GtkBin
# qui renvoie le widget contenu, ici un label.
$button->child->set_text(”Texte changé ! !” ) ;
$numclicked++ ;
}
elsif ( $numclicked == 1 )
{
# Au second click, on ôte le bouton présent. On en recrée
# un que l’on peut activer grâce à la combinaison de touches
# Alt + Q
$window->remove( $button ) ;
$button = Gtk2::Button->new_with_mnemonic(”Appuyer sur Alt+\_Q” ) ;
$button->signal_connect( ”clicked” , \&ClickedButtonEvent ) ;
$button->show() ;
$window->add( $button ) ;
$numclicked++ ;
}
elsif ( $numclicked == 2 )
{
# On recommence la manipulation précédente sauf que l’on crée
# un bouton fermer standard ! !
$window->remove( $button ) ;
$button = Gtk2::Button->new_from_stock(’gtk-close’ ) ;
$button->signal_connect( ”clicked” , \&ClickedButtonEvent ) ;
$button->show() ;
$window->add( $button ) ;
$numclicked++ ;
}
else
{
Gtk2->main_quit ;
}
}

Les boutons Toggle ou interrupteurs

Les boutons toggle sont dérivés des boutons normaux et sont très similaires sauf qu’ils n’ont que deux états possibles et qui change à l’aide d’un clic. Ils peuvent être remontés et quand vous cliquez, ils redescendent. Vous recliquez et ils remontent.

Les boutons toggle servent de base aux cases à cocher et aux boutons radios, au point que ces derniers héritent de beaucoup des appels utilisés pour les boutons toggle. Nous vous indiquerons lesquels quand nous les rencontreront.

Créer un bouton toggle

$button = Gtk2::ToggleButton->new();  
$button = Gtk2::ToggleButton->new_with_label($label);  
$button = Gtk2::ToggleButton->new_with_mnemonic($label);

Comme vous pouvez l’imaginer, cela fonctionne exactement comme pour les boutons normaux et toutes les fonctions du widget GtkButton sont utilisables avec ce type de bouton.

Pour retrouver l’état d’un widget toggle, incluant les boutons radios et les cases à cocher, nous utilisons une construction illustrée dans l’exemple ci-dessous. Cela teste l’état du toggle en accédant au domaine actif de la structure du widget toggle. Le signal qui nous intéresse émis par un bouton toggle (les boutons toggle, radio et les cases à cocher) est le signal toggled. Pour contrôler l’état de ces boutons, déclarez un gestionnaire de signal pour attraper les signal toggled et accéder à la structure afin de déterminer son état. Le rappel ressemblera à

 sub toggle_button_callback  
 {  
   $togglebutton = $_[0];  
   if ( $togglebutton->get_active )  
      {  
      # Si le contrôle arrive là, le bouton est baissé  
      }  
      else  
      {  
      # Si le contrôle arrive là, le bouton est levé  
      }  
}

Changer l’état du bouton

Pour forcer l’état d’un bouton toggle, et ses enfants, les boutons radios et les cases à cocher, utilisez :

$togglebutton->set_active( $state );

Passer une valeur vraie ou fausse comme argument précise s’il doit être en bas (pressé) ou en haut (relâché). Le défaut est en haut ou faux. Notez que si vous utilisez la fonction set_active() et que l’état est en fait changé, cela déclenchera l’émission du signal clicked par le bouton (et non toggled comme beaucoup de personnes le pensent).

Pour obtenir l’état d’un bouton, vous pouvez utiliser :

$togglebutton->get_active();

Plutôt que de changer la valeur d’un bouton toggle en contrôlant son état actif et en déclarant la valeur opposée, utiliser tout simplement la fonction :

$togglebutton->toggled();

Cette fonction émettra aussi le signal toggled.

Il existe cependant un troisième état qui n’est pas accessible en cliquant sur le bouton mais par une fonction spécifique. Ce troisième état, vous le connaissez sûrement. Le meilleur exemple est celui des éditeurs de texte : vous avez une phrase dans laquelle il y a du texte normal et du texte en gras. Si vous sélectionnez le texte en gras, le bouton permettant justement de le mettre en gras s’enfonce (en général B). Par contre si vous sélectionnez le texte normal, ce même bouton repasse à son état relâché. Venons en au troisième état, qui apparaît lorsque vous sélectionnez la phrase entière. Le bouton ne change pas d’état mais seulement d’aspect, il donne l’impression d’être inactif.

Ce changement d’aspect doit se faire manuellement, et s’effectue avec cette fonction :

$bouton->set_inconsistent($setting);

Il suffit de mettre le paramètre setting à TRUE pour donner au bouton l’aspect inactif.

Et pour connaître l’aspect du bouton, il y a tout naturellement la fonction :

$bouton->get_inconsistent();

Exemple

bouton3

# !/usr/bin/perl -w

use Gtk2 ’-init’ ;

use constant TRUE => 1 ;
use constant FALSE => 0 ;


my $window = Gtk2::Window->new( ”toplevel” ) ;
$window->signal_connect( ”delete_event” , sub { Gtk2->main_quit ; } ) ;
$window->set_title( ”Les Interrupteurs” ) ;
$window->set_border_width( 0 ) ;

my $box1 = Gtk2::VBox->new( FALSE, 0 ) ;
$box1->show() ;
$window->add( $box1 ) ;

# On crée le bouton toggle
my $button1 = Gtk2::ToggleButton->new( ”Etat relâché - Aspect normal” ) ;
$box1->pack_start( $button1, FALSE, FALSE, 0 ) ;
$button1->signal_connect( ”toggled” ,\&OnToggled) ;
$button1->show() ;

# On crée un bouton Etat
my $button2 = Gtk2::Button->new_with_label( ”Changer l’état” ) ;
$box1->pack_start( $button2, TRUE, TRUE, 0 ) ;
$button2->signal_connect( ”clicked” ,\&OnEtatClicked,$button1) ;
$button2->show() ;

# On crée un bouton Aspect
my $button3 = Gtk2::Button->new_with_label( ”Changer l’aspect” ) ;
$box1->pack_start( $button3, TRUE, TRUE, 0 ) ;
$button3->signal_connect( ”clicked” ,\&OnAspectClicked,$button1) ;
$button3->show() ;

$window->show() ;

Gtk2-¿main ;

sub OnEtatClicked{
my ($widget,$button)=@_ ;
# On récupère l’état du bouton puis on le modifie
my $etat = $button->get_active() ;
$button->set_active($etat^TRUE) ;
}

sub OnAspectClicked {
my ($widget,$button)=@_ ;
# On récupère l’aspect du bouton puis on le modifie
my $binconsistent = $button->get_inconsistent() ;
$button->set_inconsistent($binconsistent^TRUE) ;
# On émet le signal toggled pour changer le label du bouton
$button->toggled() ;
}

sub OnToggled{
my ($widget) = @_ ;
my $binconsistent = $widget->get_inconsistent() ;
my $etat = $widget->get_active() ;
# On change le texte du label
my $label = sprintf(”Etat : %s - Aspect : %s” , $etat ? ”enfoncé”  : ”relâché” , $binconsistent ? ”modifié”  : ”normal” ) ;
$widget->set_label($label) ;
}


Les cases à cocher

Les cases à cocher héritent de beaucoup de propriétés et de fonctions des boutons toggle, mais ils ont une allure différente. Plutôt que d’être des boutons avec du texte à l’intérieur, ce sont des petites cases avec le texte à leur droite. Elles sont souvent utilisées pour choisir des options oui ou non dans une application.

Les deux fonctions de création sont les mêmes que pour un bouton normal.

$button = Gtk2::CheckButton->new();  
$button = Gtk2::CheckButton->new($label);

Passer une chaîne en argument crée une case à cocher avec un label à son côté. Le contrôle de l’état de la case se fait de la même manière que pour le bouton toggle.

Les boutons radio

Nous passons maintenant au widget GtkRadioButton qui se différencie des autres boutons par la possibilité d’en grouper plusieurs. De ce fait, lors que par exemple nous avons un groupe de trois boutons, il n’y en a qu’un seul qui peut être actif. On pourrait très bien faire cela avec le widget GtkCheckButton mais cela serait beaucoup plus long à programmer. Dans la hiérarchie des widgets, GtkRadioButton dérive de GtkCheckButton.

Création d’un groupe de radio.

Afin de grouper les boutons radio, Gtk2-Perl utilise un tableau. Pour créer le premier bouton radio du groupe, il faut obligatoirement passer par une de ces fonctions :

$button =  Gtk2::RadioButton->new($group,$label);  
$button =  Gtk2::RadioButton->new_with_mnemonic($group,$label);  
$button =  Gtk2::RadioButton->new_with_label_from_widget($button,$label);

$group$ est un référence à un tableau. Au moment de la création, le bouton radio est automatiquement ajouté au tableau.

Ensuite pour rajouter les autres boutons au groupe, il y a plusieurs possibilités. La première est d’utiliser une des trois fonctions précédentes mais ce n’est pas tout, car autant pour le premier bouton du groupe, il n’est pas nécessaire d’avoir un groupe, autant pour les autres boutons cela devient obligatoire. Pour cela, GTK+ nous fournit une fonction qui permet d’obtenir le groupe auquel les boutons du groupe sont ajoutés :

$group = $button->get_group();

Avec cette fonction, nous pouvons donc connaître le groupe auquel appartient le bouton, ce qui va nous permettre d’ajouter de nouveau bouton au groupe. La troisième méthode de création permet de créer un bouton radio sans avoir à se préoccuper de connaître le groupe des boutons précédents. Il suffit de connaître un des boutons du groupe.

Exemple

L’exemple suivant crée un groupe de trois boutons radio et affiche celui qui est actif quand on clicke sur le bouton Valider.

bouton2

# !/usr/bin/perl -w

use Gtk2 ’-init’ ;

use constant TRUE => 1 ;
use constant FALSE => 0 ;


my $window = Gtk2::Window->new( ”toplevel” ) ;
$window->signal_connect( ”delete_event” , sub { Gtk2->main_quit ; } ) ;
$window->set_title( ”Radio Buttons” ) ;
$window->set_border_width( 0 ) ;

my $box1 = Gtk2::VBox->new( FALSE, 0 ) ;
$box1->show() ;

my $box2 = Gtk2::VBox->new( FALSE, 10 ) ;
$box2->set_border_width( 10 ) ;
$box1->pack_start( $box2, FALSE, FALSE, 0 ) ;
$box2->show() ;
$window->add( $box1 ) ;

# On crée un premier bouton radio que l’on place
# dans la boîte.
my $button1 = Gtk2::RadioButton->new( undef, ”bouton 1” ) ;
$box2->pack_start( $button1, FALSE, FALSE, 0 ) ;
$button1->show() ;

# On récupère le groupe auquel appartient le premier bouton.
my $group = $button1->get_group() ;

# On crée un autre bouton radio que l’on rattache au groupe.
my $button2 = Gtk2::RadioButton->new_with_mnemonic( $group, ”bouton 2” ) ;
# On veut que ce bouton soit le bouton actif par défaut.
$button2->set_active( TRUE ) ;
$box2->pack_start( $button2, TRUE, TRUE, 0 ) ;
$button2->show() ;

# Même chose mais sans passer par la variable $groupe.
my $button3 = Gtk2::RadioButton->new_with_label_from_widget($button1,”bouton 3” ) ;
$box2->pack_start( $button3, TRUE, TRUE, 0 ) ;
$button3->show() ;

# Un séparateur pour l’esthétique
my $separator = Gtk2::HSeparator->new() ;
$box1->pack_start( $separator, FALSE, FALSE, 0 ) ;
$separator->show() ;

## Le bouton valider qui lance une routine dont l’objectif
# est de nous indiquer lequel des boutons est actif.
my $button_close = Gtk2::Button->new_from_stock(’gtk-ok’ ) ;
$button_close->signal_connect( ”clicked” ,\&valider,$button1) ;
$box1->pack_start( $button_close, TRUE, TRUE, 0 ) ;
$button_close->can_default( TRUE ) ;
$button_close->grab_default() ;
$button_close->show() ;
$window->show() ;

Gtk2->main ;

sub valider{
my ($widget,$button)=@_ ;
# On récupère la référence du groupe auquel appartient le bouton
my $group = $button->get_group() ;

my $label ;

# On parcours le tableau des boutons et on affiche le bouton qui est actif.
my $but ;
foreach $but (@$group) {
if ($but->get_active) {
# On récupère le label du bouton actif
$label = $but->get_label() ;
}
}
# On affiche le tout dans une petite fenêtre de dialogue. Il faut tout d’abord
# remonter jusqu’à la fenêtre mère.
my $window = $widget->get_toplevel() ;
# On peut alors créer notre fenêtre de dialogue. Nous verrons son fonctionnement plus tard.
my $dialog = Gtk2::MessageDialog->new ($window,’modal’ ,’info’ ,’ok’ , sprintf ”Le %s est actif !” ,$label) ;
$dialog->run ;
$dialog->destroy ;
}