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

9.6. Les images

Les gtk.Image sont des structures de données qui contiennent des images. Ces images peuvent être utilisées à plusieurs endroits.

On peut créer des gtk.Image à partir de pixbufs, de pixmaps, de fichiers contenant des informations soit de type image (XPM, PNG, JPEG, TIFF, etc.) soit de type animation.

On crée un gtk.Image avec la fonction :

  image = gtk.Image()

Puis on y charge l'image en utilisant l'une des méthodes suivantes :

  image.set_from_pixbuf(pixbuf)
  image.set_from_pixmap(pixmap, mask)
  image.set_from_image(image)
  image.set_from_file(filename)
  image.set_from_stock(stock_id, size)
  image.set_from_icon_set(icon_set, size)
  image.set_from_animation(animation)

pixbuf est un GdkPixbuf, pixmap et mask sont des GdkPixmaps, image est un GdkImage, stock_id est le nom d'un GtkStockItem, icon_set est un GtkIconSet, et animation est une GdkPixbufAnimation. Quant à l'argument size (taille), il peut prendre l'une des valeurs suivantes :

 ICON_SIZE_MENU			# taille de l'icône : menu
 ICON_SIZE_SMALL_TOOLBAR	#          "        : petite barre d'outils
 ICON_SIZE_LARGE_TOOLBAR	#          "        : grande barre d'outils
 ICON_SIZE_BUTTON		#          "        : bouton
 ICON_SIZE_DND			#          "        : glisser-déposer
 ICON_SIZE_DIALOG		#          "        : boite de dialogue

Le moyen le plus simple de créer une image est d'utiliser la méthode set_from_file(), laquelle détermine automatiquement le type de l'image et le charge.

Le programme images.py illustre le chargement de plusieurs types d'images ( goal.gif, pomme-rouge.png, chaos.jpg, important.tif, ballonfoot.gif) dans des gtk.Image, que l'on place ensuite dans des boutons :

Figure 9.5. Images exemples dans des boutons

exemple images

Voici le code source :

     1   #!/usr/bin/env python
     2   
     3   # exemple images.py
     4   
     5   import pygtk
     6   pygtk.require('2.0')
     7   import gtk
     8   
     9   class ImagesExemple:
    10       # Si elle est invoquee (via le "delete_event"), cette fonction ferme l'application
    11       def fermer_application(self, widget, evnmt, data=None):
    12           gtk.main_quit()
    13           return False
    14   
    15       # Cette fonction est invoquee quand on clique sur le bouton. Elle affiche un message.
    16       def clic_bouton(self, widget, data=None):
    17           print "Clic sur le bouton %s" % data
    18   
    19       def __init__(self):
    20           # creation de la fenetre principale, et connexion du signal
    21           # delete_event a la fermeture de l'application
    22           fenetre = gtk.Window(gtk.WINDOW_TOPLEVEL)
    23           fenetre.connect("delete_event", self.fermer_application)
    24           fenetre.set_border_width(10)
    25           fenetre.show()
    26   
    27           # Une boite horizontale pour contenir les boutons
    28           boite_h = gtk.HBox()
    29           boite_h.show()
    30           fenetre.add(boite_h)
    31   
    32           animpixbuf = gtk.gdk.PixbufAnimation("goal.gif")
    33           image = gtk.Image()
    34           image.set_from_animation(animpixbuf)
    35           image.show()
    36           # un bouton pour contenir le widget image
    37           bouton = gtk.Button()
    38           bouton.add(image)
    39           bouton.show()
    40           boite_h.pack_start(bouton)
    41           bouton.connect("clicked", self.clic_bouton, "1")
    42           
    43           # creation de plusieurs gtk.Image a partir de donnees de
    44           # fichiers, et chargement dans des boutons
    45           image = gtk.Image()
    46           image.set_from_file("pomme-rouge.png")
    47           image.show()
    48           # un bouton pour contenir le widget image
    49           bouton = gtk.Button()
    50           bouton.add(image)
    51           bouton.show()
    52           boite_h.pack_start(bouton)
    53           bouton.connect("clicked", self.clic_bouton, "2")
    54   
    55           image = gtk.Image()
    56           image.set_from_file("chaos.jpg")
    57           image.show()
    58           # un bouton pour contenir le widget image
    59           bouton = gtk.Button()
    60           bouton.add(image)
    61           bouton.show()
    62           boite_h.pack_start(bouton)
    63           bouton.connect("clicked", self.clic_bouton, "3")
    64   
    65           image = gtk.Image()
    66           image.set_from_file("important.tif")
    67           image.show()
    68           # un bouton pour contenir le widget image
    69           bouton = gtk.Button()
    70           bouton.add(image)
    71           bouton.show()
    72           boite_h.pack_start(bouton)
    73           bouton.connect("clicked", self.clic_bouton, "4")
    74   
    75           image = gtk.Image()
    76           image.set_from_file("ballonfoot.gif")
    77           image.show()
    78           # un bouton pour contenir le widget image
    79           bouton = gtk.Button()
    80           bouton.add(image)
    81           bouton.show()
    82           boite_h.pack_start(bouton)
    83           bouton.connect("clicked", self.clic_bouton, "5")
    84   
    85   
    86   def main():
    87       gtk.main()
    88       return 0
    89   
    90   if __name__ == "__main__":
    91       ImagesExemple()
    92       main()

9.6.1. Les pixmaps

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 :

Figure 9.6. Exemple de pixmap dans un bouton

exemple pixmap

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 :

Figure 9.7. Exemple de fenêtre en forme de brouette

exemple brouette

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.