Vous êtes à peu près ici : Accueil  »   tutoriel PyGTK  »   PyGTK : sommaire

2.4. Le "Hello World" pas à pas

Après ces explications plutôt théoriques, revenons à présent à notre programme helloworld.py pour un examen plus détaillé.

Les lignes 9 à 76 définissent la classe HelloWorld. Celle-ci contient toutes les fonctions de rappel en tant que méthodes d'objet, ainsi qu'un constructeur (méthode d'initialisation d'instance). Attardons-nous sur les fonctions de rappel.

Aux lignes 13 et 14, on trouve la définition de la méthode de rappel salut(), qui sera invoquée par un clic sur le bouton et affichera "Salut tout le monde !" dans la console. Nous ignorons les paramètres (l'instance, le widget émetteur, et les données transmises) dans cet exemple, mais la plupart des fonctions de rappel les utilisent. Le paramètre donnees est défini avec une valeur par défaut valant None, car Pygtk ne transmettrait pas de valeur de données si elle n'est pas incluse dans l'appel à connect(). Dans un tel cas, une erreur se produirait car la fonction de rappel, qui attend obligatoirement trois paramètres, n'en recevrait que deux. Définir None comme valeur par défaut permet à la fonction de rappel d'être invoquée avec deux ou trois paramètres sans déclencher d'erreur. Dans le cas de notre exemple, on aurait pu se passer du paramètre donnees puisque la méthode salut() sera toujours appelée avec seulement deux paramètres (jamais elle ne recevra de données utilisateur). Notre prochain programme utilisera cet argument donnees pour nous dire quel bouton a été cliqué.

  def salut(self, widget, donnees=None):
      print "Salut tout le monde !"

La fonction de rappel suivante (lignes 16 à 26) est un peu spéciale. L'évènement "delete_event" se produit lorsque le gestionnaire de fenêtres envoie cet évènement à l'application. On a le choix quant à ce que l'on souhaite faire de ces évènements : les ignorer, faire quelque chose en réponse, ou simplement quitter l'application.

La valeur que l'on fait renvoyer par cette fonction de rappel fait connaitre notre décision à GTK+. Renvoyer TRUE lui indique que l'on ne veut pas que le signal "destroy" soit émis ; laissant l'application se poursuivre. En renvoyant FALSE, en revanche, nous demandons à ce que le signal "destroy" soit émis, lequel appellera le gestionnaire de signal "destroy". Les commentaires ont été retirés pour plus de clarté :

  def evnmt_delete(widget, evenement, donnees=None):
      print "Évènement delete survenu."
      return False

La fonction de rappel destroy() des lignes 28-30, entraine la sortie du programme par un appel à gtk.main_quit(). Cette fonction ordonne à GTK+ de sortir de gtk.main() lorsque le contrôle lui est rendu.

  def destroy(self, widget, donnees=None):
      print "Évènement destroy survenu."
      gtk.main_quit()

Les lignes 32 à 71 définissent la méthode d'initialisation d'instance __init__() de HelloWorld, qui crée la fenêtre et les widgets utilisés par le programme.

À la ligne 34, on crée une nouvelle fenêtre. Cependant, celle-ci ne s'affichera que lorsque GTK+ en recevra l'ordre, vers la fin du programme. On enregistre une référence à cette fenêtre dans un attribut d'instance (self.fenetre) pour pouvoir y accéder plus tard.

    self.fenetre = gtk.Window(gtk.WINDOW_TOPLEVEL)

Les lignes 41 et 46 illustrent deux exemples de connexion d'un gestionnaire de signal à un objet, en l'occurrence à la fenetre. Ici, on capte les signaux "delete_event" et "destroy". Le premier est émis lorsque l'on utilise le gestionnaire de fenêtres pour fermer la fenêtre, ou par un appel à la méthode destroy() de GtkWidget. Le second est émis lorsque dans le gestionnaire du "delete_event", on renvoie FALSE.

    self.fenetre.connect("delete_event", self.evnmt_delete)
    self.fenetre.connect("destroy", self.destroy)    

La ligne 49 précise un attribut d'un objet conteneur, ici la fenetre, pour lui donner un espace vide de 10 pixels de large le long de son périmètre intérieur, où aucun widget ne pourra être placé. D'autres fonctions similaires existent, nous nous y intéresserons dans le Chapitre 18, Définir les attributs des widgets.

    self.fenetre.set_border_width(10)

À la ligne 52, on crée un bouton et on en enregistre une référence dans self.bouton. Le bouton portera l'étiquette "Salut tout le monde !" lors de son affichage.

    self.bouton = gtk.Button("Salut tout le monde !")

À la ligne 57, on attache un gestionnaire de signal au bouton de sorte que la méthode de rappel salut() soit invoquée lorsqu'il émettra le signal "clicked". Nous n'avons aucune donnée à transmettre à salut(), aussi nous passons la valeur None (rien) en lieu de paramètre donnees. Comme l'on pourrait s'y attendre, le signal "clicked" est émis lorsque l'on clique sur le bouton de la souris. Indiquer la valeur du paramètre de données utilisateur None n'est pas exigé et pourrait être omis. On appellerait alors la fonction de rappel avec un paramètre de moins.

    self.bouton.connect("clicked", self.salut, None)

Nous voulons aussi utiliser ce bouton pour quitter notre programme. Comme nous l'avons déjà vu, le signal "destroy" peut être émis par le gestionnaire de fenêtres, mais également par le programme lui-même, ce qu'illustre la ligne 62. Lorsque l'on clique sur le bouton, celui-ci appelle tout d'abord la méthode de rappel salut(), puis la suivante,dans le même ordre où elles ont été définies. On peut attacher autant de fonctions de rappel que l'on souhaite à un objet, elles seront toutes exécutées dans l'ordre dans lequel on les a connectées.

Puisque nous voulons utiliser la méthode destroy() de GtkWidget et que celle-ci n'accepte qu'un argument (le widget à détruire — la fenetre dans notre cas), nous employons la méthode connect_object et lui transmettons une référence à notre fenêtre. La méthode connect_object transmettra le paramétre fenetre comme premier argument au lieu du bouton.

L'appel de la méthode destroy() de gtk.Widget déclenchera l'émission du signal "destroy" par la fenêtre. Ceci entrainera à son tour l'appel de la méthode destroy() de notre classe HelloWorld pour terminer le programme.

    self.bouton.connect_object("clicked", gtk.Widget.destroy, self.fenetre)

La ligne 65 est un appel de placement, ce que nous verrons en détail un peu plus tard dans le Chapitre 4, Le placement des widgets . Quoi qu'il en soit, cet appel est assez facile à comprendre : il indique juste à GTK+ que le bouton doit être placé dans la fenêtre, où il s'affichera. À noter qu'un conteneur GTK+ ne peut contenir qu'un seul widget. D'autres widgets, destinés à en recevoir plusieurs, de différentes manières, seront décrits plus loin.

    self.fenetre.add(self.bouton)

Maintenant que tout est mis en place comme nous le voulions (les gestionnaires de signaux, le bouton placé dans sa fenêtre...), nous demandons à GTK+ d'afficher les widgets à l'écran (lignes 68 et 71). Le widget fenetre est affiché en dernier de sorte qu'il apparaisse avec son bouton déjà placé, et non que la fenêtre s'affiche vide puis que le bouton apparaisse à l'intérieur, (même si l'on ne s'en apercevrait pas avec un si petit exemple).

    self.bouton.show()

    self.fenetre.show()    

Les lignes 73 à 76 définissent la méthode boucle() qui appelle la fonction gtk.main().

    def boucle(self):
        gtk.main()

Les lignes 80 à 82 permettent au programme de se lancer automatiquement s'il est appelé directement ou en tant qu'argument de l'interpréteur Python. La ligne 81 crée une instance de la classe HelloWorld et en enregistre une référence dans la variable salut. Enfin, la ligne 82 appelle la méthode boucle() de HelloWorld afin d'initialiser la boucle de traitement d'évènements de GTK+.

    if __name__ == "__main__":
        salut = HelloWorld()
        salut.boucle()

Quand on clique sur un bouton GTK+, le widget émet un signal "clicked". Afin d'utiliser cette information, notre programme prévoit un gestionnaire de signal qui devra la capter et passer le contrôle à une fonction de notre choix. Dans notre exemple, quand on clique sur le bouton créé, la méthode salut()est appelée avec None comme argument. Ensuite, le gestionnaire suivant du signal "clicked" prend la main : il appelle la fonction destroy() du widget avec la fenêtre comme argument, entrainant par là l'émission du signal "destroy" par cette dernière. Ce signal est intercepté et appelle la méthode destroy() de notre classe HelloWorld.

On peut aussi choisir de fermer la fenêtre par le gestionnaire de fenêtres. Le signal "delete_event" sera alors émis et son gestionnaire invoquera la fonction de rappel evnmt_delete(). Si cette dernière renvoie TRUE, la fenêtre sera laissée telle quelle et rien ne se passera. Si, au contraire, elle renvoie FALSE, GTK+ émettra le signal "destroy" qui, évidemment, appellera la fonction de rappel du même nom. Et l'on quittera GTK.