=====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====
[[http://u-classroom.net/cours/langages/python4.tgz|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 **Dialog**s) 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 :
- le widget à insérer ;
- True si l'espace doit être rempli ;
- True si le widget doit lui même remplir l'espace alloué ;
- une marge supplémentaire pour le widget.
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 :
- le constructeur (gtk.CheckButton);
- l'héritage. Celà vous permet d'accéder rapidement aux méthodes des classes mères, notamment gtk.ToggleButton, dont gtk.CheckBox n'est qu'une variante;
- le détail des propriétés, styles, méthodes et signaux.
=====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).