Les pixmaps sont des structures de données qui contiennent des images. Ces images
peuvent être utilisées à plusieurs endroits, mais le sont le plus
souvent sous la forme d'icônes pour le bureau X ou bien de pointeurs.
Un pixmap de seulement 2 couleurs est un bitmap. Des routines additionnelles existent
pour manipuler ce cas à part relativement commun.
Pour comprendre les pixmaps, il vous faut comprendre le fonctionnement du
système X Window. Sous X, il n'est pas nécessaire que les applications
tournent sur l'ordinateur qui dialogue avec l'utilisateur. Les différentes
applications, appelées "clients", communiquent toutes avec un programme
qui se charge de l'affichage de la partie graphique ainsi que de la gestion du clavier et
de la souris. Ce programme, qui dialogue directement avec l'utilisateur, est appelé
un "serveur d'affichage" ou "serveur X". Du fait que la communication
peut avoir lieu dans le cadre d'un réseau, il est important que certaines informations
soient conservées par le serveur X. Les pixmaps, par exemple, sont stockés
dans sa mémoire. Cela signifie que, une fois que des valeurs de pixmaps sont
définies, elles n'ont plus besoin d'être à nouveau transmises dans
le réseau ; une simple commande sera envoyée pour "afficher le pixmap
numéro XYZ à tel endroit". Même si vous n'utilisez pas X avec GTK
en ce moment, l'utilisation de structures comme les pixmaps fera tourner convenablement
vos programmes sous X.
Pour utiliser des pixmaps dans PyGTK, il nous faut d'abord construire un
GdkPixmap en nous servant des fonctions gtk.gdk de PyGTK. Les pixmaps
peuvent être créés soit à partir de données en
mémoire, soit à partir de données lues dans un fichier. Nous
allons examiner les différents appels de création.
pixmap = gtk.gdk.pixmap_create_from_data(window, data, width, height, fg, bg)
On utilise la routine ci-dessus pour crééer un pixmap
à partir de données (data) en mémoire. Sa profondeur
de couleur est donnée par depth. Si depth vaut
-1, la profondeur de couleur sera dérivée de celle de
window (fenêtre). Pour représenter les couleurs, chaque pixel
utilisera autant de bits de données que mentionné à l'argument
depth (profondeur). width (largeur) et height
(hauteur) sont spécifiés en pixels. L'argument window doit
faire référence à une GdkWindow réalisée,
les ressources d'un pixmap n'ayant de sens que dans le contexte de l'écran où
il doit être affiché. fg et bg sont les couleurs
de premier plan (foreground) et d'arrière plan (background)
du pixmap.
Les pixmaps peuvent être créés à partir de fichiers XPM
grâce à la fonction :
pixmap, masque = gtk.gdk.pixmap_create_from_xpm(window, transparent_color, filename)
Le format XPM est un représentation lisible d'un pixmap, destinée au
système X Window. Il s'agit d'un format trés répandu et de nombreux
utilitaires existent pour créer des fichiers images dans ce format. Dans la fonction
pixmap_create_from_xpm(), le premier argument est un type GdkWindow —
la majorité des widgets GTK possèdent une fenêtre GdkWindow
sous-jacente, récupérable par l'attribut window du widget. Le fichier
est spécifié à l'argument filename (nom du fichier).
Il doit contenir une image au format XPM à charger dans la structure
pixmap. Le masque est un bitmap qui indique les bits de
pixmap devant être opaques ; il est créé par la fonction.
Tous les autres pixels sont colorés en utilisant la couleur scpécifiée
par transparent_color (couleur transparente). Vous trouverez ci-dessous un
exemple d'utilisation de cette fonction.
Les pixmaps peuvent également être créés à partir de
données en mémoire, et ce avec la fonction suivante :
pixmap, masque = gtk.gdk.pixmap_create_from_xpm_d(window, transparent_color, data)
Cette fonction permet d'incorporer de petites images à un programme sous la forme
de données au format XPM. Un pixmap sera créé à partir de ces
données-là plutôt qu'en lisant celles d'un fichier. Voici un exemple de
ces données :
donnees_xpm = [
"16 16 3 1",
" c None",
". c #000000000000",
"X c #FFFFFFFFFFFF",
" ",
" ...... ",
" .XXX.X. ",
" .XXX.XX. ",
" .XXX.XXX. ",
" .XXX..... ",
" .XXXXXXX. ",
" .XXXXXXX. ",
" .XXXXXXX. ",
" .XXXXXXX. ",
" .XXXXXXX. ",
" .XXXXXXX. ",
" .XXXXXXX. ",
" ......... ",
" ",
" "
]
Enfin, la dernière possibilité permet de créer un pixmap vierge,
prêt pour les opérations de dessin :
pixmap = gtk.gdk.Pixmap(window, width, height, depth=-1)
window est soit une GdkWindow soit None. Dans le premier
cas, depth (profondeur) peut valoir -1 afin d'indiquer que la profondeur
doit être déterminée par la fenêtre. Dans le second cas,
depth devra être spécifié.
Le programme pixmap.py est un
exemple d'utilisation d'un pixmap dans un bouton. La Figure 9.6 en montre le
résultat :
Voici le code source :
1 #!/usr/bin/env python
2
3 # exemple pixmap.py
4
5 import pygtk
6 pygtk.require('2.0')
7 import gtk
8
9 # Donnees XPM d'une icone "Ouvrir Fichier"
10 donnees_xpm = [
11 "16 16 3 1",
12 " c None",
13 ". c #000000000000",
14 "X c #FFFFFFFFFFFF",
15 " ",
16 " ...... ",
17 " .XXX.X. ",
18 " .XXX.XX. ",
19 " .XXX.XXX. ",
20 " .XXX..... ",
21 " .XXXXXXX. ",
22 " .XXXXXXX. ",
23 " .XXXXXXX. ",
24 " .XXXXXXX. ",
25 " .XXXXXXX. ",
26 " .XXXXXXX. ",
27 " .XXXXXXX. ",
28 " ......... ",
29 " ",
30 " "
31 ]
32
33 class ExemplePixmap:
34 # Si elle est invoquee (via le "delete_event"), cette fonction ferme l'application
35 def fermer_application(self, widget, evnmt, data=None):
36 gtk.main_quit()
37 return False
38
39 # Fonction invoquee par un clic sur le bouton. Elle affiche juste un message.
40 def clic_bouton(self, widget, data=None):
41 print "Clic sur le bouton"
42
43 def __init__(self):
44 # creation de la fenetre principale, et connexion du signal
45 # delete_event a la fermeture de l'application
46 fenetre = gtk.Window(gtk.WINDOW_TOPLEVEL)
47 fenetre.connect("delete_event", self.fermer_application)
48 fenetre.set_border_width(10)
49 fenetre.show()
50
51 # venons-en a la creation du pixmap a partir des donnees XPM
52 pixmap, masque = gtk.gdk.pixmap_create_from_xpm_d(fenetre.window,
53 None,
54 donnees_xpm)
55
56 # Creation d'un widget gtk.Image pour contenir le pixmap
57 image = gtk.Image()
58 image.set_from_pixmap(pixmap, masque)
59 image.show()
60
61 # Creation d'un bouton pour contenir le gtk.Image
62 bouton = gtk.Button()
63 bouton.add(image)
64 fenetre.add(bouton)
65 bouton.show()
66
67 bouton.connect("clicked", self.clic_bouton)
68
69 def main():
70 gtk.main()
71 return 0
72
73 if __name__ == "__main__":
74 ExemplePixmap()
75 main()
Les pixmap ont malgré tout cet inconvénient que l'objet affiché
est toujours rectangulaire, quelle que soit l'image. On aimerait bien pouvoir créer
des bureaux ou des applications avec des icônes aux formes plus naturelles. Des boutons
ronds seraient par exemple bienvenus dans l'interface d'un jeu. C'est ici qu'entrent en jeu
les fenêtres adaptées.
Il s'agit en fait simplement d'un pixmap dont les pixels d'arrière-plan sont
transparents. Ainsi, lorsque l'image d'arrière-plan est multicolore, on ne l'encombre
pas avec la bordure rectangulaire inadaptée de notre icône. Le programme
d'exemple brouette.py affiche une
image représentant une brouette pleine sur le bureau. La
Figure 9.7
montre cette brouette par dessus une fenêtre de terminal :
Voici le code source de brouette.py
:
1 #!/usr/bin/env python
2
3 # exemple brouette.py
4
5 import pygtk
6 pygtk.require('2.0')
7 import gtk
8
9 # XPM
10 BrouettePleine_xpm = [
11 "48 48 64 1",
12 " c None",
13 ". c #DF7DCF3CC71B",
14 "X c #965875D669A6",
15 "o c #71C671C671C6",
16 "O c #A699A289A699",
17 "+ c #965892489658",
18 "@ c #8E38410330C2",
19 "# c #D75C7DF769A6",
20 "$ c #F7DECF3CC71B",
21 "% c #96588A288E38",
22 "& c #A69992489E79",
23 "* c #8E3886178E38",
24 "= c #104008200820",
25 "- c #596510401040",
26 "; c #C71B30C230C2",
27 ": c #C71B9A699658",
28 "> c #618561856185",
29 ", c #20811C712081",
30 "< c #104000000000",
31 "1 c #861720812081",
32 "2 c #DF7D4D344103",
33 "3 c #79E769A671C6",
34 "4 c #861782078617",
35 "5 c #41033CF34103",
36 "6 c #000000000000",
37 "7 c #49241C711040",
38 "8 c #492445144924",
39 "9 c #082008200820",
40 "0 c #69A618611861",
41 "q c #B6DA71C65144",
42 "w c #410330C238E3",
43 "e c #CF3CBAEAB6DA",
44 "r c #71C6451430C2",
45 "t c #EFBEDB6CD75C",
46 "y c #28A208200820",
47 "u c #186110401040",
48 "i c #596528A21861",
49 "p c #71C661855965",
50 "a c #A69996589658",
51 "s c #30C228A230C2",
52 "d c #BEFBA289AEBA",
53 "f c #596545145144",
54 "g c #30C230C230C2",
55 "h c #8E3882078617",
56 "j c #208118612081",
57 "k c #38E30C300820",
58 "l c #30C2208128A2",
59 "z c #38E328A238E3",
60 "x c #514438E34924",
61 "c c #618555555965",
62 "v c #30C2208130C2",
63 "b c #38E328A230C2",
64 "n c #28A228A228A2",
65 "m c #41032CB228A2",
66 "M c #104010401040",
67 "N c #492438E34103",
68 "B c #28A2208128A2",
69 "V c #A699596538E3",
70 "C c #30C21C711040",
71 "Z c #30C218611040",
72 "A c #965865955965",
73 "S c #618534D32081",
74 "D c #38E31C711040",
75 "F c #082000000820",
76 " ",
77 " .XoO ",
78 " +@#$%o& ",
79 " *=-;#::o+ ",
80 " >,<12#:34 ",
81 " 45671#:X3 ",
82 " +89<02qwo ",
83 "e* >,67;ro ",
84 "ty> 459@>+&& ",
85 "$2u+ > ",
87 "Oh$;ya *3d.a8j,Xe.d3g8+ ",
88 " Oh$;ka *3d$a8lz,,xxc:.e3g54 ",
89 " Oh$;kO *pd$%svbzz,sxxxxfX..&wn> ",
90 " Oh$@mO *3dthwlsslszjzxxxxxxx3:td8M4 ",
91 " Oh$@g& *3d$XNlvvvlllm,mNwxxxxxxxfa.:,B* ",
92 " Oh$@,Od.czlllllzlmmqV@V#V@fxxxxxxxf:%j5& ",
93 " Oh$1hd5lllslllCCZrV#r#:#2AxxxxxxxxxcdwM* ",
94 " OXq6c.%8vvvllZZiqqApA:mq:Xxcpcxxxxxfdc9* ",
95 " 2r<6gde3bllZZrVi7S@SV77A::qApxxxxxxfdcM ",
96 " :,q-6MN.dfmZZrrSS:#riirDSAX@Af5xxxxxfevo",
97 " +A26jguXtAZZZC7iDiCCrVVii7Cmmmxxxxxx%3g",
98 " *#16jszN..3DZZZZrCVSA2rZrV7Dmmwxxxx&en",
99 " p2yFvzssXe:fCZZCiiD7iiZDiDSSZwwxx8e*>",
100 " OA1666 >=01-kuu666> ",
112 " ,6ky& &46-10ul,66, ",
113 " Ou0<> o66y66By7=xu664 ",
115 " <> +66uv,zN666* ",
117 " 566,xxj669 ",
118 " 4666FF666> ",
119 " >966666M ",
120 " oM6668+ ",
121 " *4 ",
122 " ",
123 " "
124 ]
125
126 class ExempleBrouette:
127 # Si elle est invoquee (via le "delete_event"), cette fonction ferme l'application
128 def fermer_application(self, widget, evnmt, data=None):
129 gtk.main_quit()
130 return False
131
132 def __init__(self):
133 # Creation de la fenetre principale et connexion du signal "delete_event"
134 # a la fermeture de l'application. Notez que la fenetre principale n'aura
135 # pas de barre de titre car nous la definissons comme popup.
136 fenetre = gtk.Window(gtk.WINDOW_POPUP)
137 fenetre.connect("delete_event", self.fermer_application)
138 fenetre.set_events(fenetre.get_events() | gtk.gdk.BUTTON_PRESS_MASK)
139 fenetre.connect("button_press_event", self.fermer_application)
140 fenetre.show()
141
142 # Venons-en a la creation du pixmap et du widget gtk.Image
143 pixmap, masque = gtk.gdk.pixmap_create_from_xpm_d(
144 fenetre.window, None, BrouettePleine_xpm)
145 image = gtk.Image()
146 image.set_from_pixmap(pixmap, masque)
147 image.show()
148
149 # Pour afficher l'image, on va la placer dans un widget fixe
150 wfixe = gtk.Fixed()
151 wfixe.set_size_request(200, 200)
152 wfixe.put(image, 0, 0)
153 fenetre.add(wfixe)
154 wfixe.show()
155
156 # Ici nous masquons tout sauf l'image elle-meme
157 fenetre.shape_combine_mask(masque, 0, 0)
158
159 # On affiche la fenetre
160 fenetre.set_position(gtk.WIN_POS_CENTER_ALWAYS)
161 fenetre.show()
162
163 def main():
164 gtk.main()
165 return 0
166
167 if __name__ == "__main__":
168 ExempleBrouette()
169 main()
Pour rendre la brouette sensible à la pression d'un bouton de la souris, on a
connecté son signal "button_press_event" à la méthode
fermer_application() (lignes 138-139), laquelle fait se terminer le programme.