[précédent][précédent-bas][fin][haut]
Tous les programmes se trouvent dans le répertoire exemples.
Pour découvrir Gtk2-Perl, nous allons écrire le programme le plus court et le plus simple possible. Celui-ci créera une fenêtre de 200 pixels sur 200 que l’on ne pourra pas fermer si ce n’est en la “tuant” à partir du shell.

Pour lancer le programme, on peut écrire perl minimum.pl. Le fenêtre qui apparaît peut ne pas ressembler exactement à l’image ci-dessus. GTK+ est, parmi d’autres choses, “thémable”. C’est-à-dire que l’utilisateur décide du style des widgets, des couleurs et icônes à utiliser, les polices, etc... L’exécution ci-dessus utilisait le thème par défaut. Quoi qu’il en soit, la barre de titre dépend du gestionnaire de fenêtres choisi ou de l’OS.
Nous avons donc ici la structure minimale d’une application écrite en Gtk2-Perl :
Entre ces deux lignes, nous placerons tout ce qui compose notre application. Ici, nous avons juste créé puis affiché une fenêtre en écrivant :
my $fenetre = Gtk2::Window->new('toplevel');
$fenetre->show; |
L’argument 'toplevel' signifie que nous voulons une fenêtre qui reprenne le placement et les décoration du gestionnaire de fenêtre. Plutôt que de créer un fenêtre de taille 0 × 0, une fenêtre sans enfant est règlée à la taille de 200 × 200 par défaut ainsi on peut la manipuler.

Maintenant, voyons si nous ne pouvons pas cheminer à travers le programme et lui donner du sens.
use Gtk2 '-init'; doit être inclus dans tout programme Gtk2-Perl. Cela permet à Perl d’utiliser les variables, les fonctions, les structures, etc...définies par GTK. Dans le même temps, cela initialise le module Gtk2 et met en place quelques éléments comme l’aspect par défaut, la couleur et les déclencheurs de signaux par défaut. Cela peut-être facilement combiné avec d’autres directives use comme use strict ; .
Les variables TRUE et FALSE correspondent à des valeurs booléennes. Elles sont définies pour rendre le code plus lisible.
Gtk::Window->new() crée une nouvelle fenêtre. Le window manager décide comment la décorer (avec des choses comme la barre de titre) et où la placer. Les autres widgets de l’application seront placés à l’intérieur. Vous pouvez avoir plusieurs fenêtres par programme. L’argument indique à X le type de fenêtre dont il s’agit. Les fenêtres toplevel n’ont pas de fenêtre parent et ne peuvent être contenues par aucune fenêtre. Vous pouvez également créer des fenêtres de dialogue avec new Gtk::Dialog().
La fonction set_border_width() prendra un conteneur (comme une fenêtre) et placera de l’espace autour du contenu. Cela évitera à votre application d’être trop “tassée”. Le nombre passé en argument est la largeur (en pixel) de la bordure créée. Essayez différentes valeurs.
new Gtk::Button crée un nouveau bouton. Ici, nous en avons créé un avec un label texte. Que ce serait-il passé si nous n’avions pas spécifié de texte à mettre sur le bouton ? Essayez et voyez par vous même. Remarquez la taille du bouton et de la fenêtre quand vous le faîtes ? GTK redimensionnera automatiquement les widgets sauf si vous lui dîtes de ne pas le faire (cela inclus la fenêtre). Pour cette raison, il ne sert à rien de s’inquiéter du style ou de la taille de la police que l’utilisateur peut avoir définis par défaut. Donnez juste la disposition à GTK et laissez le faire le reste. Pour plus d’informations sur les boutons voir la section les concernant.
signal_connect relie un évènement ou un signal à une routine. Un exemple serait d’appuyer sur le bouton de la souris. En terme de profane, quand un évènement ou un signal est généré, GTK regarde si cet évènement possède une routine enregistrée pour ce widget, si c’est le cas, il exécute cette routine. Si aucune routine n’est enregistrée, il ne se passe rien.
Dans notre exemple, le premier argument de signal_connect est une chaîne indiquant l’évènement que nous voulons enregistrer et le second argument est une référence à la routine à appeler si l’évènement se produit. Certains évènements peuvent nécessiter différents arguments.
La fonction add() ajoute un widget dans un conteneur (ici,la fenêtre ). Si nous n’avions pas fait cela, nous n’aurions pas vu le bouton parce qu’il n’aurait pas été dans la fenêtre.
Le fonction show() rend la fenêtre visible. N’exécutez pas show() tant que toutes les propriétés du widget ne sont pas définies. Vous devriez toujours montrer les widgets enfants avant les widgets parents (ici, rendre visible le bouton avant la fenêtre qui le contient). La manière dont la fenêtre apparaît tout d’un coup rend le programme plus professionnel.
Gtk2->main déclenche le processus de contrôle des évènements GTK. Il s’agit d’une ligne que vous verrez dans toutes les applications Gtk2-Perl. Quand le contrôle atteint ce point, GTK se mettra en sommeil, attendant les évènements X ( comme les boutons ou les touches pressés), les délais ou les notifications de fichier E/S qui peuvent se produire. Imaginez cela comme une boucle infinie dont on sort par l’appel Gtk2->main_quit().
Une interface graphique est composée d’éléments (fenêtre, cadres, boutons...) appelés widgets. Ceux-ci peuvent émettre des signaux. Ce ne sont pas les mêmes que les signaux d’un système Unix et ils ne sont pas implémentés en les utilisant bien que la terminologie soit presque identique. Quand on clique sur un bouton, il émet le signal 'clicked'. Gtk en prend note en le plaçant dans une liste. Si on veut que ce click déclenche une action, il faut relier ce signal à une fonction qui sera appelée dès que le signal sera émis. En simplifiant, il faut considérer le programme comme un régulateur qui centralise tous les évènements qui se produisent et à qui on peut demander de nous prévenir si tel ou tel évènement a eu lieu.
Pour relier un signal à une fonction, on procède ainsi :
$object->signal_connect('signal_name',\&signal_func);
$object->signal_connect(signal_name=>\&signal_func); $object->signal_connect('signal_name',\&signal_func,$donnee_optionnelle...); $object->signal_connect('signal_name',\&signal_func,@donnees_optionnelles); |
En Perl, les deux premières formes sont identiques ainsi que les deux suivantes car Perl envoit tous les arguments sous la forme d’une seule liste de scalaires. Bien sûr, vous pouvez envoyer autant d’éléments par liste que vous le désirez.
La variable à gauche du signal_connect() est le widget qui émettra le signal. Le premier argument est une chaîne de caractères représentant le signal dont vous aimeriez enregistrer le rappel de signal. Le second argument est la routine que vous voulez appeler. Cette routine est appelée rappel de signal ou fonction de rappel. Si vous passez des arguments à la routine, vous les précisez en les ajoutant à la fin de la liste d’arguments. Tout ce qui est après le second argument est passé en tant que liste, c’est pourquoi vous pouvez vous permettre de passer autant d’arguments que vous le souhaitez.
Si vous ne comprenez pas les références Perl, souvenez-vous que les routines sont précédées par un \& et que vous ne pouvez pas placer des parenthèses après le nom de la routine.
Pour les rappels de signaux associés avec uniquement un signal et composés de quelques lignes, il est courant de voir quelque chose comme ceci :
$object->signal_connect("signal_name",sub{faire_quelque_chose;});
|
Une routine est habituellement définie par :
fonction_de_rappel
{ my($widget,$donnee)=@_; ... } |
Le premier argument envoyé à un rappel de signal sera toujours le widget émetteur et le reste des arguments sont des données optionnelles envoyées par la fonction signal_connect() . Souvenez-vous que Perl ne vous oblige pas à déclarer ou à utiliser les arguments envoyés à une routine.
En plus du mécanisme des signaux décrit précédemment, il y a un ensemble d’évènements qui reflètent les mécanismes des évènements X. Par exemple, si l’utilisateur ferme la fenêtre principale, c’est le gestionnaire de fenêtres qui enverra un message à l’application.
Les évènements suivants peuvent également être reliés à une fonction de rappel :
event
button_press_event button_release_event scroll_event motion_notify_event delete_event destroy_event expose_event key_press_event key_release_event enter_notify_event leave_notify_event configure_event focus_in_event focus_out_event map_event unmap_event property_notify_event selection_clear_event selection_request_event selection_notify_event proximity_in_event proximity_out_event visibility_notify_event client_event no_expose_event window_state_event selection_received selection_get drag_begin_event drag_end_event drag_data_delete drag_motion drag_drop drag_data_get drag_data_received |
Afin de connecter une fonction de rappel à l’un de ces évènements, on utilise signal_connect() de la même manière que pour connecter un signal, sauf que l’on écrit le nom de l’évènement à la place du nom du signal. Le dernier argument passé au rappel de signal est une structure d’évènement ainsi au début de votre fonction, vous devriez dire :
my($widget,$evenement,$donnée)=@_;
|
ou si vous voulez passer un ensemble de données :
my($widget,@data)=@_;
my $event=shift(@data); |
Un évènement est une structure qui comporte plusieurs champs. Il y a en particulier le champs type qui est une chaîne de caractères qui identifie l’évènement et qui appartient à la liste suivante :
'nothing'
'delete' 'destroy' 'expose' 'motion_notify' 'button_press' '2button_press' '3button_press' 'button_release' 'key_press' 'key_release' 'enter_notify' 'leave_notify' 'focus_change' 'configure' 'map' 'unmap' 'property_notify' 'selection_clear' 'selection_request' 'selection_notify' 'proximity_in' 'proximity_out' 'drag_enter' 'drag_leave' 'drag_motion' 'drag_status' 'drop_start 'drop_finished' 'client_event' 'visibility_notify' 'no_expose' 'window_state' 'setting' |
Il y a également le champs button qui contient un nombre indiquant le bouton pressé ( typiquement 1, 2 ou 3 ) et le champs key qui indique la touche pressée ( s’il y en a une ). Cela permet de déterminer facilement la cause d’un évènement. Par exemple, cela fut-il causé par un bouton pressé ? si oui, lequel ?
sub some_event
{ my ($widget,@donnees)=@_; my $evenement=shift(@donnees); if((defined($evenement->type)) and($evenement->type eq 'button_press')) { if($evenement->button==3) { #click_droit } else { # pas_un_click_droit } } } |
Gardez à l’esprit que le code précédent ne fonctionne que si le rappel est lié à l’un des évènements mentionnés ci-dessus. Les signaux n’envoient pas une structure d’évènement ainsi, à moins que vous ne connaissiez exactement le nombre d’arguments envoyés, vous n’avez pas besoin de l’information sur la structure d’un évènement. Je milite pour ne pas connecter un signal et un évènement au même retour.
La valeur de retour de la fonction signal_connect() est un “tag” qui identifie la fonction de rappel. Vous pouvez avoir autant de rappels par signal ou par objet que vous le souhaitez et ils seront exécutés les uns après les autres dans l’ordre ou ils ont été attaché.
Si vous voulez émettre un signal spécifique, vous pouvez le faire en appelant l’une des fonctions suivantes :
$widget->signal_emit($id);
$widget->signal_emit_by_name($nom_du_signal); |
L’argument de la première forme est le “id tag” qui est retourné par signal_connect() . L’argument de la seconde forme est une chaîne identifiant le nom du signal. Ainsi beaucoup de widgets ont des méthodes qui émettent des signaux les plus courants. Par exemple, la méthode destroy() émettra le signal 'destroy' et la méthode activate() le signal 'activate'.
Ce “id tag” vous permet également de supprimer un retour de la liste en utilisant signal_disconnect() comme ceci :
$widget->signal_disconnect($id);
|
Si vous voulez ôter tous les gestionnaires d’un widget, vous pouvez appeler la fonction :
$widget->signal_handlers_destroy();
|
Cet appel se passe de commentaires. Il enlève simplement tous les gestionnaires de l’objet passés en tant que premier argument.
Vous pouvez débrancher temporairement des gestionnaires avec :
$widget->signal_handler_block($callback_id);
$widget->signal_handler_block_by_func(\&callback,$donnee); $widget->signal_handler_block_by_data($donnee); $widget->signal_handler_unblock($callback_id); $widget->signal_handler_unblock_by_func(\&callback,$donnee); $widget->signal_handler_unblock_by_data($donnee); |
Voici un aperçu des fonctions utilisées pour connecter ou déconnecter un gestionnaire pour chacun des signal_connect disponibles. Vous trouverez plus de détails dans la documentation Gtk.
$id=$object->signal_connect($nom_du_signal,\&function,@optional_data);
$id=$object->signal_connect_after($nom_du_signal,\&function,@optional_data); $id=$object->signal_connect_object($nom_du_signal,\&function,$slot_object); $id=$object->signal_connect_object_after($nom_du_signal,\&function,$slot_object); #Je ne suis pas sûr de celle-là $id=$object->signal_connect_full($name,\&function,$callback_marshal,@optional_data, \&destroy_function,$object_signal,$after); #Je ne suis pas sûr de celles-là non plus $id=$object->signal_connect_object_while_alive($signal,\&function,$alive_object); $id=$object->signal_connect_while_alive($signal,\&function,@optional_data,$alive_object); $object->signal_disconnect($id); $object->signal_disconnect_by_func(\&function,@optional_data); |

Un bon exercice serait d’ajouter un troisième bouton “quitter”. Vous pourriez également jouer avec les options de le méthode pack_start() quand vouz aurez lu le chapître suivant. Essayez de redimensionner la fenêtre et observez son comportement.
[précédent][précédent-bas][début][haut]