Introduction

Le but de ce cours est de présenter certains éléments fondamentaux de pygtk par le biais d'exemples concrêts. Présenter toutes les possibilités de GTK n'aurait pas de sens, il semble plus judicieux de découvrir les bases et de se référer à la documentation ensuite.

Exemples

Téléchargez les exemples que nous utiliserons.

Les bases

Les widgets

La plupart des éléments graphiques de GTK sont des objets héritant d'une classe 'Widget'. Chaque widget de la bibliothèque gtk possède également des attributs spécifiques, en particulier ce qu'ils affichent à l'écran, mais aussi leur façon de réagir aux actions de l'utilisateur.

Pour info, la classe Widget hérite elle même de la classe GObject (vous trouverez le détail des différents héritages dans /usr/share/gtk-doc/html/pygtk/class-hierarchy.html). GObject provient de la libglib qui (pour résumer grossièrement) permet une programmation orientée objet en C. Elle a surtout été conçue comme une bibliothèque permettant de créer facilement des bindings (tels que PyGTK).

Voyons un premier exemple (class1.py).

Les 3 premières lignes permettent d'importer gtk, et en particulier la version 2.x de cette bibliothèque. On définit ensuite une classe dont le constructeur construit tout simplement une fenêtre (vide). Les fenêtres (et dérivés, comme les Dialogs) sont les éléments premier d'une application GTK.

self.w = gtk.Window()

Cette ligne crée l'objet, mais il faut ensuite l'afficher grâce à la méthode 'show()'. Ceci est valable pour n'importe quel widget. La méthode 'hide()' cache l'objet. Notre fenêtre existe donc, et est affichée... ou presque. Il nous faut également démarrer GTK, en appelant la boucle principale grâce à

gtk.main()

/usr/share/gtk-doc/html/pygtk/class-gtkwidget.html contient la documentation sur la classe Widget, notamment ses méthodes. Une grande partie d'entre elles ne sont nécessaires que pour une utilisation avancée de GTK, que nous n'aborderons pas ici.

Les signaux

A chaque fois qu'il se passe quelque chose sur l'interface, un ou des signaux sont reçus/envoyés. Un clic sur un bouton, la saisie de texte, le déplacement de la souris, etc. sont des évènements qui provoquent ces signaux. Cliquer sur la 'croix' d'une fenêtre émet le signal 'destroy' sur la fenêtre. On peut bien évidemment définir ce qui se passe en cas de réception de ce signal. C'est ce qui est fait dans class2.py :

self.w.connect("destroy", self.end)

La méthode 'connect' permet ici d'appeler la méthode 'end' de notre classe lorsque le signal 'destroy' est reçu par notre fenêtre.

Dans notre exemple, la méthode 'end' appelle simplement 'gtk.main_quit', ce qui a pour effet de nous faire sortir de la boucle principale, et de quitter normalement le programme.

Vous noterez que le 'w', second argument de la méthode 'end()' est simplement le widget qui a reçu le signal. Nous en reparlerons plus tard.

Conteneurs

Elément unique

Certains widgets sont des conteneurs, ils peuvent inclure d'autres widgets. Les fenêtres en sont un exemple. Regardons l'exemple 3 (class3.py) qui insert un bouton dans la fenêtre. Une fois notre bouton créé grâce à 'gtk.Button()', nous l'ajoutons simplement grâce à la méthode 'add()' de l'objet w. On connecte le boutton au signal 'clicked', qui permettra de fermer la fenêtre.

Ce type de conteneur a bien évidemment des limites, puisqu'on ne peut y inclure qu'un seul widget.

Les boîtes

Les boîtes ('HBox' et 'VBox') permettent d'inclure plusieurs éléments, de manière soit horizontale, soit verticale. Une fois qu'une boîte est créée, on y ajoute les éléments, soit au début, soit à la fin, grâce au méthode 'pack_start' et 'pack_end'. Regardons l'exemple 4 (class4.py).

La création d'une boîte est faite grâce à HBox() ou VBox() suivant le sens voulu. Ces méthodes prennent deux arguments. Le premier doit être 'True' si chaque case de la boîte doit avoir la même dimension. Le second est la taille de la marge entre les éléments (en pixels).

'pack_start' et 'pack_end' prennent 4 arguments :

Jouez avec ces différentes valeurs pour voir le résultat.

Vous remarquez que chaque boutton est connecté à un signal "clicked", qui permet d'appeler la même fonction à chaque fois. La second argument passé à la fonction est le widget cliqué, et le résultat de cette fonction varie selon cet argument.

Les tableaux

Les tableaux (Table) fonctionnent de manière similaire aux boîtes mais permettent évidemment des placements suivant les 2 dimensions.

Exemples de widgets

Regardez l'exemple 5 (classe5.py) pour avoir un (petit) aperçu de widgets 'simples'.

Lire la documentation

Vous savez tout sur GTK ! Il serait très certainement inutile de passer en revue toutes les possibilités offertes par GTK. La documentation est plutôt bien faite et claire, une fois que l'on connait les bases (ce qui est votre cas maintenant). Jettons un coup d'oeil à la page concernant les CheckBtn : /usr/share/gtk-doc/html/pygtk/class-gtkcheckbutton.html. Cette page a l'air vide, mais vous y trouvez pourtant tout ce qu'il faut :

Widgets avancés

treeview

Les 'treeview' sont des widgets utilisés pour lister des éléments. Ils font intervenir des 'tree stores', des listes plus ou moins complexes d'éléments multiples. Un exemple d'utilisation de ces treeview est la liste des paquets de synaptic. On peut y inclure toutes sortes d'éléments (checkbox, texte...). Nous allons voir un exemple simple (class6.py).

Première étape : prévoir. Un treeview est en général dynamique et s'agrandit selon les données insérées. Il faut donc prévoir les dépassement d'écran. C'est que nous faisons en utilisant une fenêtre 'scrollée' (ScrolledWindow). Ce widget permet d'ajouter des barres de défilements au widget qu'il va inclure (c'est un conteneur).

Deuxième étape : créer la liste des éléments. En effet, les éléments ne sont pas créés dans le widget, mais dans un 'TreeStore'. Ceci permet notamment d'avoir un unique conteneur d'éléments et plusieurs représentations.

store = gtk.TreeStore(gobject.TYPE_INT, gobject.TYPE_STRING)

crée la liste, contenant 2 éléments par ligne (ce sont de simple type int et str mais à la sauce gobject). Pour parcourir cette liste et y ajouter nous passons par 2 étape. On définit tout d'abord l'élément (iter) sur lequel on veut travailler. Dans notre cas, le suivant sur la liste (qui sera le premier puisque l'on n'a rien dans la liste pour le moment) :

iter = store.append(None)

On utilise ensuite cet élément pour insérer les valeurs :

store.set(iter, 0, 1, 1, "one")

Etape suivante : créer l'interface. On va la créer à partir de notre liste, donc :

treeview = gtk.TreeView(store)

Il nous faut maintenant créer chaque colonne. Comme nous l'avons vu plus haut, un TreeView peut contenir plusieurs types d'éléments. Il nous faut donc préciser que les colonnes contiendront du text. On utilise pour ça un widget CellRendererText. On crée une colonne en l'utilisant :

column = gtk.TreeViewColumn("Entier", renderer, text=0)

Le premier argument est le titre de la colonne, le second le renderer, et le troisième l'identité de la colonne (on a aura plusieurs). On ajoute ensuite la colonne au treeview :

treeview.append_column(column)

Et voilà !

ComboBox

Nous avons vu un combobox tout à l'heure, avec une manière de l'utiliser. On peut également l'utiliser avec un TreeStore. Plus exactement un TreeModel, mais ces deux objets sont similaires. Voyez l'exemple class7.py.

On utilise également un renderer pour afficher du texte, et on utilise l'élément 1 de notre liste pour afficher les données. Mais la liste entière reste accessible, comme vous pouvez le voir dans la méthode show (cliquez le bouton pour afficher le réultat dans la console).