Cet article est le cinquième d'une série destinée à vous faire découvrir le langage Python. Le mois dernier nous avons exploré les différentes fonctionnalités fournies par les modules Python les plus classiques ainsi que quelques astuces courantes de programmation permises par le langage. Ce mois-ci, nous allons voir comment utiliser Python pour écrire rapidement des applications Gtk+ ou GNOME. Cet article suppose que le lecteur connait déjà les bases de la programmation Gtk+/GNOME.
Avant d'aller plus loin, vous allez devoir vous assurer que les interfaces
("les bindings") Gtk+ et GNOME pour Python sont bien installées
sur votre machine. Si vous avez la chance d'utiliser la distribution Debian
GNU/Linux sur votre machine, il vous suffit de taper la commande 'apt-get
install python-gtk python-gnome' pour vérifier que ces deux
paquetages sont bien installés ou de les installer à la volée
le cas échéant. Si vous utilisez une autre distribution,
consultez dans les références de cet article la liste des
URLs de logiciels à télécharger.
Pour vérifier que les modules Python correspondant fonctionnent
correctement, il vous suffit de lancer l'interpréteur et de taper
l'instruction :
>>> import gtk, gnome
>>>
Si l'interpréteur vous rend le prompt sans afficher aucun message,
c'est tout bon. Bravo!
Si le message
"No display information -- gtk_init not called"
est affiché, cela signifie tout simplement que vous avez oublié
de positionner correctement votre variable d'environnement $DISPLAY
(la valeur ":0" convient dans la plupart des cas, sauf si vous utilisez
un interpréteur Python situé sur une machine distante).
Enfin, dans le cas où vous obtiendriez un message se terminant
par :
"RuntimeError: cannot open display",
vérifiez que l'interpréteur a bien le droit d'ouvrir
une connexion vers votre serveur X. A ce moment, la commande "xhost
+" tapée à partir d'un terminal ayant les droits d'accès
au serveur X permettra de régler ce problème.
Si par contre vous obtenez un autre message d'erreur, c'est qu'il y
a un problème d'installation.
Bases de la programmation d'interfaces graphiques
À la différence de la programmation "traditionnelle",
la programmation d'interfaces graphiques avec des toolkits évolués
(dont Gtk+ fait bien sûr partie) repose sur un modèle de programmation
événementiel. C'est-à-dire que lorsque le programme
a fini de mettre en place tous les éléments de l'interface
graphique, il appelle une fonction qui va se charger d'intercepter tous
les événements (mouvements de la souris, clics, entrées
aux clavier, etc) reçus par le programme et de les dispatcher vers
les fonctions qui doivent les traiter. Ce mécanisme utilise les
callbacks,
ou fonctions de rappel : Lorsque l'on défini un élément
de l'interface graphique (une widget), on lui associe un ou plusieurs
callbacks qui seront appelés lorsque des événements
déterminés s'appliqueront à cette widget.
Voyons cela de plus près avec un premier exemple :
|
01 : #!/usr/bin/python
02 : 03 : from gtk import * 04 : 05 : def hello(*args): 06 : print "Hello World" 07 : window.destroy() 08 : 09 : def destroyfunc(*args): 10 : window.hide() 11 : mainquit() 12 : 13 : window = GtkWindow(WINDOW_TOPLEVEL) 14 : window.connect("destroy", destroyfunc) 15 : window.set_border_width(10) 16 : 17 : button = GtkButton("Hello World") 18 : button.connect("clicked", hello) 19 : window.add(button) 20 : button.show() 21 : window.show() 22 : 23 : mainloop() |
À la ligne 3, on importe le module Gtk+ qui va permettre
d'utiliser des primitives graphiques. On défini ensuite (lignes
5 à 11) deux fonctions de callback qui seront utilisés quelques
lignes plus loin.
La mise en place des éléments de l'interface commence
réellement à la ligne 13 : On commence par créer une
fenêtre, que l'on déclare de type 'WINDOW_TOPLEVEL', c'est-à-dire
qu'elle sera prise en charge directement par le gestionnaire de fenêtres.
Ensuite, on connecte l'événement 'destroy' de la fenêtre
'window' à la fonction destroyfunc(). Cette fonction sera
appelée dans le cas où l'on ferme directement la fenêtre
à partir du gestionnaire de fenêtres (typiquement en cliquant
sur la croix en haut à droite de la fenêtre).
Ensuite, on utilise la méthode set_border_width() pour
indiquer que l'on désire que cette fenêtre ait une bordure
de 10 pixels de large sur ses quatre bords. Ce n'est absolument pas indispensable,
mais ça fait beaucoup plus joli ;-)
L'unique fenêtre de notre application étant définie,
passons maintenant à son contenu. Nous allons pour le moment nous
limiter à afficher un seul bouton qui permettra simplement de quitter
l'application. Celui-ci est créé à la ligne 17. La
ligne suivante utilise le même mécanisme que la ligne 14 pour
lui assigner un callback : lorsque l'on cliquera sur ce bouton, la fonction
'hello' sera appelée. Celle-ci se contente d'afficher un message
sur la sortie standard, puis envoie elle-même l'événement
destroy à la fenêtre. Maintenant, il ne reste plus
qu'à indiquer que l'on désire que le bouton soit placé
à l'intérieur de notre belle fenêtre (ligne 19), puis
à demander successivement l'affichage de nos deux éléments
(lignes 20 et 21). Deux choses importantes à noter à ce sujet
:
- D'une part les widgets créés ne sont jamais affichés
automatiquement. Il faut systématiquement leur appliquer la méthode
show(), pour qu'ils apparaissent.
- D'autre part, et bien que le problème ne se pose pas sur les
programmes aussi simple que celui que nous venons de voir, il est d'usage
de demander en premier l'affichage des widgets les plus internes. En effet,
il est visuellement plus agréable de voir apparaître d'un
coup une fenêtre contenant un bouton plutôt que de voir apparaître
une fenêtre vide dans laquelle viendra de placer un bouton une fraction
de seconde plus tard.
Enfin, pour terminer notre application, nous devons exécuter la fonction mainloop. Celle-ci ne se termine jamais (a moins bien sur que le programme ne soit interrompu par un ctrl-C) et a pour rôle d'intercepter les événements en provenance du serveur X, et de les analyser pour pouvoir déclencher les callbacks appropriés.
Comme vous l'avez déjà constaté par vous même
si vous avez bien suivi les articles précédents, l'interface
Gtk+ fournie par Python est entièrement orientée objet. Cela
apporte non seulement une grande convivialité, mais permet de développer
une application graphique en très peu de temps. Il existe actuellement
plusieurs "grosses" applications graphiques développées entièrement
grâce au couple Python/Gtk+, par exemple le jeu de solitaire PySol
ou le programme de dessin vectoriel Sketch.
Pour être tout à fait honnête, Python/Gtk+ comporte
cependant un petit inconvénient : L'API est très mal documentée.
Ce problème est largement atténué du fait que l'API
reste extrêmement proche de l'API C (à l'orientation objet
près), d'autre part le code source du module contient un exemple
extrêmement complet (testgtk.py) qui utilise toutes les widgets Gtk+,
auquel on peut se référer en cas de doute.
Maintenant, passons à une application GNOME. Par rapport à
Gtk+, GNOME fourni un grand nombre de widgets, et en général
de fonctionnalités qui simplifient encore plus la vie du programmeur.
|
01 : #!/usr/bin/python
02 : 03 : from gtk import * 04 : from gnome.ui import * 05 : 06 : def about(widget): 07 : about = GnomeAbout('Test de GNOME-Python', 'v3.14159', 08 : 'Copyright (c) 2000 LMag France', 09 : ['Vincent <vincent@debian.org>', 'Auteur 2', 'Auteur 3'], 10 : "Encore un programme d'exemple.") 11 : about.show() 12 : 13 : def menus(): 14 : file_menu = [UIINFO_ITEM_STOCK('Nouveau',None,None,STOCK_MENU_NEW), 15 : UIINFO_SEPARATOR, 16 : UIINFO_ITEM_STOCK('Quitter',None,mainquit,STOCK_MENU_QUIT)] 17 : help_menu = [UIINFO_ITEM_STOCK('A Propos',None,about,STOCK_MENU_ABOUT)] 18 : menubar = [UIINFO_SUBTREE('Fichier',file_menu), 19 : UIINFO_SUBTREE('Help',help_menu)] 20 : return menubar 21 : 22 : def toolbar(): 23 : toolbar_info = [UIINFO_ITEM_STOCK('Nouveau', None, None, STOCK_PIXMAP_NEW), 24 : UIINFO_SEPARATOR, 25 : UIINFO_ITEM_STOCK('Ouvrir', None, None, STOCK_PIXMAP_OPEN), 26 : UIINFO_ITEM_STOCK('Enregistrer', None, None, STOCK_PIXMAP_SAVE)] 27 : return toolbar_info 28 : 29 : def main(): 30 : window = GnomeApp('hellognome.py', 'Test de GNOME-Python') 31 : window.create_menus(menus()) 32 : window.create_toolbar(toolbar()) 33 : text = GtkText(None, None) 34 : text.set_editable(TRUE) 35 : window.set_contents(text) 36 : window.connect('destroy', mainquit) 37 : window.show() 38 : mainloop() 39 : 40 : if __name__ == '__main__': 41 : main() |
Cette application hellognome.py est à peu de choses près
l'application GNOME la plus simple possible en tenant compte du fait qu'elle
comporte quand même les éléments classiques que l'on
retrouve dans toutes les applications, comme une barre de menu, une boîte
d'informations sur le programme 'A propos', la partie principale de la
fenêtre de l'application comportant une widget GtkText. À
ce titre, c'est un bon point de départ pour construire des applications
plus complexes.
Examinons le code source de plus près :
Pour commencer, en plus d'importer l'interface de la bibliothèque
Gtk+, on importe également l'interface des widgets graphiques définies
par GNOME (gnome.ui).
Des lignes 6 à 11, on défini la fonction about(),
qui affiche la fenêtre 'A propos...' lorsque l'entrée correspondante
du menu principal est sélectionnée. Cette fonction prend
comme paramétres une liste de chaînes : le nom du logiciel,
sa version, son copyright, la liste de ses auteurs et une présentation
sommaire du logiciel.
Viennent ensuite les définitions des menus et de la barre d'outils.
Celles-ci reprennent d'assez près la syntaxe utilisée avec
l'interface GNOME pour le langage C.
Enfin, la fonction main() est définie et c'est elle
qui va s'occuper de mettre en place tous les éléments de
l'interface : Tout d'abord, on crée une nouvelle application GNOME
grâce à la fonction GnomeApp(). Ensuite, on appelle
successivement les méthodes create_menus() et create_toolbar() de
l'application pour la création effective des menus et de la barre
d'outils. Les lignes 33 à 35 quant à elles créent
la widget GtkText qui est utilisée dans la partie principale de
la fenêtre de l'application. Maintenant, il ne reste plus qu'à
rendre les éléments graphiques visibles et lancer la boucle
principale de gestion des événements.
Terminons maintenant avec un exemple plus élaboré qui
vous permettra d'épater vos ami(e)s ;-)
Il consiste à créer une applet pour le tableau de bord
GNOME. Contrairement à ce que l'on pourrait croire, créer
des applets n'est pas plus compliqué de de programmer une application
GNOME standard. En effet, bien que les applets et le tableau de bord communiquent
entre eux via le protocole CORBA, tout ce mécanisme de communication
inter-processus est transparent pour le programmeur (sauf bien sûr
dans l'éventualité où celui-ci désire réellement
"mettres les mains dans le cambouis", mais c'est rarement le cas).
|
01 : #!/usr/bin/python
02 : 03 : from gnome.applet import * 04 : from gtk import * 05 : from time import * 06 : 07 : def update_label(): 08 : str = strftime("%a %d %b\n%T", localtime(time())) 09 : label.set_text(str) 10 : return TRUE 11 : 12 : app = AppletWidget("horloge-python") 13 : 14 : frame = GtkFrame() 15 : label = GtkLabel() 16 : label.set_padding(4,4) 17 : update_label() 18 : 19 : frame.add(label) 20 : label.show() 21 : 22 : frame.show() 23 : app.add(frame) 24 : app.set_tooltip("Très belle horloge en Python") 25 : app.show() 26 : 27 : timeout_add(1000, update_label) 28 : 29 : mainloop() |
Ceci étant dit, regardons le code source de plus près
:
- lignes 1 à 5 : rien de spécial, si ce n'est que l'on
importe également le module 'gnome.applet' qui est indispensable
pour les programmes de type applet.
- lignes 7 à 10 : définition de la fonction update_label()
qui a pour rôle de remettre à jour toutes les secondes le
label qui indique la date et l'heure.
- ligne 12 : c'est là que commencent les choses sérieuses
: la fonction AppletWidget crée l'applet elle-même.
- lignes 14 à 25 : définition et configuration des widgets
qui composent l'application. Celle-ci se compose simplement d'une frame
contenant un label texte. Notez au passage la ligne 24 qui permet de déclarer
la chaîne de caractères à utiliser dans la bulle d'aide
correspondant à l'applet.
- ligne 27 : on arme un timer qui aura comme rôle d'appeler à
intervalles réguliers la fonction update_label(), pour
tenir l'affichage à jour. L'intervalle entre deux appels est donné
en millièmes de secondes.
- ligne 29 : enfin, pour pour tous les programmes Gtk, on appelle la
fonction mainloop().
Mine de rien, le couple Python/GNOME permet de créer une application graphique simple, bien qu'utile et fonctionnelle en moins de 30 lignes de code! Qui dit mieux?
Voila, grâce à ce cinquième article, vous devriez
maintenant être capable d'impressioner vos ami(e)s en créant
des applications graphiques complexes en quelques heures ;-)
|
Python 1.6b1 :
Après les versions alpha, voici la première bêta de Python 1.6. Parmi les nouveauté, on note : - Le support de l'Unicode a été terminé. - Le module de gestion des expressions régulières a été entièrement réécrit. - Beaucoup de bugs ont été corrigés. |
|
Site web :
http://www.python.org/ Listes de diffusion Python : - En Français : http://www.aful.org/mailman/listinfo/python - En Anglais : http://www.python.org/psa/MailingLists.html - Listes des développeurs (pour ceux d'entre vous qui sont intéressés par des discussions d'assez haut niveau technique; attention, ce n'est pas une liste de diffusion destinée au support) http://www.python.org/sigs/ Groupes de discussion : comp.lang.python comp.lang.python.announce GNOME : http://www.gnome.org/ GNOME-Python : ftp://ftp.daa.com.au/pub/james/python/ Python-Gtk : ftp://ftp.gtk.org/pub/gtk/python/ Gtk+ http://www.gtk.org/ Tutorial Gtk+ : http://www.gtk.org/tutorial/ (Une version en Français de ce tutorial, traduite par Éric Jacoboni, est disponible dans les sources de Gtk+) PySol : http://wildsau.idv.uni-linz.ac.at/mfx/pysol/ Sketch : http://sketch.sourceforge.net/ Documentation Python en Français (traduite par Olivier Berger, Bruno Liénard et Daniel Calvelo Aros) : http://perso.club-internet.fr/olberger/python/python.html Livres: "Learning python" par Mark Lutz & David Ascher, éditions O'Reilly "Programming python" par Mark Lutz, éditions O'Reilly |
Utilisateur de GNU/Linux depuis 1993, Vincent
Renardias a commencé a s'impliquer activement dans le développement
à partir de 1996 : Développeur de la distribution Debian,
auteur de la traduction Française de The GIMP et de l'environnement
GNOME, créateur du groupe d'utilisateurs Linux de Marseille (PLUG),
... Actuellement responsable technique de la société Echo,
il continue à contribuer activement au système GNU/Linux.
Vincent Renardias <vincent@echo.fr> |