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

12.2. Les méthodes pour dessiner

Il existe un ensemble de méthodes pour dessiner sur le "canevas" d'une zone de dessin. Ces méthodes peuvent être utilisées pour n'importe quelle sous-classe de gtk.gdk.Drawable (soit un gtk.gdk.Window, soit un gtk.gdk.Pixmap). Les voici :

  drawable.draw_point(gc, x, y) # dessiner un point

...où gc est le contexte graphique utilisé pour le dessin,

x et y sont les coordonnées du point.

  drawable.draw_line(gc, x1, y1, x2, y2) # dessiner une ligne

... où gc est le contexte graphique.

x1 et y1 sont les coordonnées du point de départ, x2 et y2 les coordonnées du point d'arrivée.

  drawable.draw_rectangle(gc, filled, x, y, largeur, hauteur) # dessiner un rectangle

... où gc est le contexte graphique.

filled est un booléen indiquant si le rectangle doit être rempli avec la couleur de premier plan (TRUE) ou non (FALSE).

x et y sont les coordonnées du coin haut gauche du rectangle.

largeur et hauteur indiquent la largeur et hauteur du rectangle.

  drawable.draw_arc(gc, filled, x, y, largeur, hauteur, angle1, angle2) # dessiner un arc de cercle

... où gc est le contexte graphique.

filled est un booléen indiquant si le rectangle doit être rempli avec la couleur de premier plan (TRUE) ou non (FALSE).

x et y sont les coordonnées du coin haut gauche du rectangle inscrit. largeur and hauteur indiquent la largeur et hauteur du rectangle inscrit.

angle1 est l'angle de départ de l'arc, en partant de la position 3 heures, dans le sens inverse des aiguilles d'une montre, par pas de 1/64 degré.

angle2 est la fin de l'angle de l'arc, relatif à angle1, par pas de 1/64 degré.

  drawable.draw_polygon(gc, filled, points) # dessiner un polygone

... où gc est le contexte graphique.

filled est un booléen indiquant si le rectangle doit être rempli avec la couleur de premier plan (TRUE) ou non (FALSE).

points est un tuple contenant une liste de paires de coordonnées, par exemple [ (0,0), (2,5), (3,7), (4,11) ], désignant les point devant être reliés pour dessiner un polygone.

  drawable.draw_string(font, gc, x, y, string) # dessiner une chaîne de caractères

  drawable.draw_text(font, gc, x, y, string) # dessiner un texte

... où font est le gtk.gdk.Font utilisé pour dessiner la chaîne de caractères.

gc est le contexte graphique.

x et y sont les coordonnées du point où commence le dessin de la chaîne, c'est à dire, la ligne de base de gauche.

string est la chaîne de caractères à dessiner.

Note

Les deux méthodes draw_string() et draw_text() sont démodées. À la place, il faut plutôt utiliser un pango.Layout avec la méthode draw_layout().

  drawable.draw_layout(gc, x, y, layout) # dessiner un affichage

... où gc est le contexte graphique.

x et y sont les coordonnées du point où débute le dessin du layout.

layout est le pango.Layout qui va être dessiné.

  drawable.draw_drawable(gc, src, xsrc, ysrc, xdest, ydest, largeur, hauteur) # dessiner un dessinable

... où gc est le contexte graphique.

src est le dessinable origine.

xsrc and ysrc are the coordinates of the top left rectangle in the source drawable.

xdest and ydest sont les coordonnées du coin haut gauche de la zone de dessin.

largeur et hauteur sont la largeur et hauteur du dessinable d'origine à copier sur le dessinable. Si l'un de ces paramètres vaut -1, on utilise la largeur ou hauteur complète du dessinable.

  drawable.draw_image(gc, image, xsrc, ysrc, xdest, ydest, largeur, hauteur) # dessiner une image

... où gc est le contexte graphique.

image est l'image origine.

xsrc et ysrc sont les coordonnées du coin supérieur gauche du rectangle dans le dessinable source

xdest et ydest sont les coordonnées du coin supérieur gauche dans la zone de dessin.

largeur et hauteur sont la largeur et hauteur de la zone dessinable origine qui doit être copiée sur le dessinable (drawable). Si l'un de ces paramètres vaut -1, on utilise la largeur ou hauteur complète de l'image.

  drawable.draw_points(gc, points) # dessiner des points

... où gc est le contexte graphique.

points est une liste ou un tuple contenant les tuples de paires de coordonnées, par exemple [ (0,0), (2,5), (3,7), (4,11) ] désignant les points à dessiner.

  drawable.draw_segments(gc, segs) # dessiner des segments de ligne

... où gc est le contexte graphique.

segs est une liste ou un tuple des coordonnées des points de départ et de fin des segments à dessiner, contenues dans un tuple, par exemple [ (0,0, 1,5), (2,5, 1,7), (3,7, 1,11), (4,11, 1,13) ]

  drawable.draw_lines(gc, points) # dessiner une ligne brisée

... où gc est le contexte graphique.

points est une liste ou un tuple contenant les tuples de paires de coordonnées, par exemple [ (0,0), (2,5), (3,7), (4,11) ] désignant les points à relier par des lignes.

  drawable.draw_rgb_image(gc, x, y, largeur, hauteur, dith, rgb_buf, rowstride)

  drawable.draw_rgb_32_image(gc, x, y, largeur, hauteur, dith, buf, rowstride)

  drawable.draw_gray_image(gc, x, y, largeur, hauteur, dith, buf, rowstride)

... où gc est le contexte graphique.

x et y sont les coordonnées du coin supérieur gauche du rectangle qui contient l'image.

largeur and hauteur sont la largeur et la hauteur du rectangle qui contient l'image.

dith est le mode de diffusion (tramage) décrit ci-dessous

Pour la méthode draw_rgb_image(), le paramètre rgb_buf représente les données de l'image RGB, codifiées dans une chaîne sous forme de séquence de triplets de pixels RGB de 8 bits. Pour la méthode draw_rgb_32_image(), buf représente les données de l'image RGB, codifiées dans une chaîne sous forme de séquence de triplets de pixels RGB de 8 bits avec 8 bits de padding (4 caractères par pixel RGB). Pour la méthode draw_gray_image(), buf représente les données de l'image codifiées dans une chaîne de pixels de 8 bits.

rowstride est le nombre de caractères depuis le début d'une rangée jusqu'au début de la rangée suivante de l'image. Normalement sa valeur par défaut est 3 * largeur pour la méthode draw_rgb_image(), 4 * largeur pour la méthode draw_rgb_32_image() et largeur pour la méthode draw_gray_image(). Si rowstride vaut 0, la ligne sera répétée hauteur fois.

Voici les différents modes de diffusion (dither) :

  RGB_DITHER_NONE    # Ne pas utiliser de diffusion.

  RGB_DITHER_NORMAL  # Utiliser la diffusion si seulement 8 bits par pixels (ou moins).

  RGB_DITHER_MAX     # Utiliser la diffusion si 16 bits par pixels (ou moins).

Le programme exemple drawingarea.py illustre l'utilisation de la plupart des méthodes de la DrawingArea. Il place une zone de dessin (DrawingArea) dans une fenêtre défilante ScrolledWindow et ajoute des règles horizontales et verticales (Ruler). La Figure 12.1, « Exemple de Drawing Area » montre le programme après lancement :

Figure 12.1. Exemple de Drawing Area

Exemple de Drawing Area

Le code source ci-dessous drawingarea.py ci-dessous utilise l'image pixmap gtk.xpm

     1   #!/usr/bin/env python
     2   # -*- coding:utf-8 -*-
     3   # exemple drawingarea.py
     4   
     5   import pygtk
     6   pygtk.require('2.0')
     7   import gtk
     8   import operator
     9   import time
    10   import string
    11   
    12   class ExempleZoneDessin:
    13       def __init__(self):
    14           fenetre = gtk.Window(gtk.WINDOW_TOPLEVEL)
    15           fenetre.set_title("Exemple de zone de dessin")
    16           fenetre.connect("destroy", lambda w: gtk.main_quit())
    17           self.zone_dessin = gtk.DrawingArea()
    18           self.zone_dessin.set_size_request(400, 300)
    19           self.stylepango = self.zone_dessin.create_pango_layout("")
    20           self.fenetre_defil = gtk.ScrolledWindow()
    21           self.fenetre_defil.add_with_viewport(self.zone_dessin)
    22           self.table = gtk.Table(2,2)
    23           self.reglehoriz = gtk.HRuler()
    24           self.reglevert = gtk.VRuler()
    25           self.reglehoriz.set_range(0, 400, 0, 400)
    26           self.reglevert.set_range(0, 300, 0, 300)
    27           self.table.attach(self.reglehoriz, 1, 2, 0, 1, yoptions=0)
    28           self.table.attach(self.reglevert, 0, 1, 1, 2, xoptions=0)
    29           self.table.attach(self.fenetre_defil, 1, 2, 1, 2)
    30           fenetre.add(self.table)
    31           self.zone_dessin.set_events(gtk.gdk.POINTER_MOTION_MASK |
    32                                gtk.gdk.POINTER_MOTION_HINT_MASK )
    33           self.zone_dessin.connect("expose-event", self.rappel_zone_dessin_expose)
    34           def a_bouge(ruler, event):
    35               return ruler.emit("motion_notify_event", event)
    36           self.zone_dessin.connect_object("motion_notify_event", a_bouge,
    37                                    self.reglehoriz)
    38           self.zone_dessin.connect_object("motion_notify_event", a_bouge,
    39                                    self.reglevert)
    40           self.ajuste_hor = self.fenetre_defil.get_hadjustment()
    41           self.ajuste_ver = self.fenetre_defil.get_vadjustment()
    42           def rappel_valeur(ajuste, regle, horiz):
    43               if horiz:
    44                   span = self.fenetre_defil.get_allocation()[3]
    45               else:
    46                   span = self.fenetre_defil.get_allocation()[2]
    47               l,u,p,m = regle.get_range()
    48               v = ajuste.value
    49               regle.set_range(v, v+span, p, m)
    50               while gtk.events_pending():
    51                   gtk.main_iteration()
    52           self.ajuste_hor.connect('value-changed', rappel_valeur, self.reglehoriz, True)
    53           self.ajuste_ver.connect('value-changed', rappel_valeur, self.reglevert, False)
    54           def rappel_taille_fixee(wid, allocation):
    55               x, y, w, h = allocation
    56               l,u,p,m = self.reglehoriz.get_range()
    57               m = max(m, w)
    58               self.reglehoriz.set_range(l, l+w, p, m)
    59               l,u,p,m = self.reglevert.get_range()
    60               m = max(m, h)
    61               self.reglevert.set_range(l, l+h, p, m)
    62           self.fenetre_defil.connect('size-allocate', rappel_taille_fixee)
    63           self.zone_dessin.show()
    64           self.reglehoriz.show()
    65           self.reglevert.show()
    66           self.fenetre_defil.show()
    67           self.table.show()
    68           fenetre.show()
    69   
    70       def rappel_zone_dessin_expose(self, zone_dessin, event):
    71           self.style = self.zone_dessin.get_style()
    72           self.contexte_graph = self.style.fg_gc[gtk.STATE_NORMAL]
    73           self.trace_point(10,10)
    74           self.trace_points(110, 10)
    75           self.trace_ligne(210, 10)
    76           self.trace_lignes(310, 10)
    77           self.trace_segments(10, 100)
    78           self.trace_rectangles(110, 100)
    79           self.trace_arcs(210, 100)
    80           self.trace_pixmap(310, 100)
    81           self.trace_polygone(10, 200)
    82           self.trace_image_rgb(110, 200)
    83           return True
    84   
    85       def trace_point(self, x, y):
    86           self.zone_dessin.window.draw_point(self.contexte_graph, x+30, y+30)
    87           self.stylepango.set_text("Point")
    88           self.zone_dessin.window.draw_layout(self.contexte_graph, x+5, y+50, self.stylepango)
    89           return
    90   
    91       def trace_points(self, x, y):
    92           points = [(x+10,y+10), (x+10,y), (x+40,y+30),
    93                     (x+30,y+10), (x+50,y+10)]
    94           self.zone_dessin.window.draw_points(self.contexte_graph, points)
    95           self.stylepango.set_text("Points")
    96           self.zone_dessin.window.draw_layout(self.contexte_graph, x+5, y+50, self.stylepango)
    97           return
    98   
    99       def trace_ligne(self, x, y):
   100           self.zone_dessin.window.draw_line(self.contexte_graph, x+10, y+10, x+20, y+30)
   101           self.stylepango.set_text("Ligne")
   102           self.zone_dessin.window.draw_layout(self.contexte_graph, x+5, y+50, self.stylepango)
   103           return
   104   
   105       def trace_lignes(self, x, y):
   106           points = [(x+10,y+10), (x+10,y), (x+40,y+30),
   107                     (x+30,y+10), (x+50,y+10)]
   108           self.zone_dessin.window.draw_lines(self.contexte_graph, points)
   109           self.stylepango.set_text("Lignes")
   110           self.zone_dessin.window.draw_layout(self.contexte_graph, x+5, y+50, self.stylepango)
   111           return
   112   
   113       def trace_segments(self, x, y):
   114           segments = ((x+20,y+10, x+20,y+70), (x+60,y+10, x+60,y+70),
   115               (x+10,y+30 , x+70,y+30), (x+10, y+50 , x+70, y+50))
   116           self.zone_dessin.window.draw_segments(self.contexte_graph, segments)
   117           self.stylepango.set_text("Segments")
   118           self.zone_dessin.window.draw_layout(self.contexte_graph, x+5, y+80, self.stylepango)
   119           return
   120   
   121       def trace_rectangles(self, x, y):
   122           self.zone_dessin.window.draw_rectangle(self.contexte_graph, False, x, y, 80, 70)
   123           self.zone_dessin.window.draw_rectangle(self.contexte_graph, True, x+10, y+10, 20, 20)
   124           self.zone_dessin.window.draw_rectangle(self.contexte_graph, True, x+50, y+10, 20, 20)
   125           self.zone_dessin.window.draw_rectangle(self.contexte_graph, True, x+20, y+50, 40, 10)
   126           self.stylepango.set_text("Rectangles")
   127           self.zone_dessin.window.draw_layout(self.contexte_graph, x+5, y+80, self.stylepango)
   128           return
   129   
   130       def trace_arcs(self, x, y):
   131           self.zone_dessin.window.draw_arc(self.contexte_graph, False, x+10, y, 70, 70,
   132                                     0, 360*64)
   133           self.zone_dessin.window.draw_arc(self.contexte_graph, True, x+30, y+20, 10, 10,
   134                                     0, 360*64)
   135           self.zone_dessin.window.draw_arc(self.contexte_graph, True, x+50, y+20, 10, 10,
   136                                     0, 360*64)
   137           self.zone_dessin.window.draw_arc(self.contexte_graph, True, x+30, y+10, 30, 50,
   138                                     210*64, 120*64)
   139           self.stylepango.set_text("Arcs")
   140           self.zone_dessin.window.draw_layout(self.contexte_graph, x+30, y+80, self.stylepango)
   141           return
   142   
   143       def trace_pixmap(self, x, y):
   144           pixmap, mask = gtk.gdk.pixmap_create_from_xpm(
   145               self.zone_dessin.window, self.style.bg[gtk.STATE_NORMAL], "gtk.xpm")
   146   
   147           self.zone_dessin.window.draw_drawable(self.contexte_graph, pixmap, 0, 0, x+15, y+25,
   148                                          -1, -1)
   149           self.stylepango.set_text("Pixmap")
   150           self.zone_dessin.window.draw_layout(self.contexte_graph, x+5, y+80, self.stylepango)
   151           return
   152   
   153       def trace_polygone(self, x, y):
   154           points = [(x+10,y+60), (x+10,y+20), (x+40,y+70),
   155                     (x+30,y+30), (x+50,y+40)]
   156           self.zone_dessin.window.draw_polygon(self.contexte_graph, True, points)
   157           self.stylepango.set_text("Polygone")
   158           self.zone_dessin.window.draw_layout(self.contexte_graph, x+5, y+80, self.stylepango)
   159           return
   160   
   161       def trace_image_rgb(self, x, y):
   162           b = 80*3*80*['\0']
   163           for i in range(80):
   164               for j in range(80):
   165                   b[3*80*i+3*j] = chr(255-3*i)
   166                   b[3*80*i+3*j+1] = chr(255-3*abs(i-j))
   167                   b[3*80*i+3*j+2] = chr(255-3*j)
   168           buff = string.join(b, '')
   169           self.zone_dessin.window.draw_rgb_image(self.contexte_graph, x, y, 80, 80,
   170                                    gtk.gdk.RGB_DITHER_NONE, buff, 80*3)
   171           self.stylepango.set_text("Image RGB")
   172           self.zone_dessin.window.draw_layout(self.contexte_graph, x+5, y+80, self.stylepango)
   173           return
   174   
   175   def main():
   176       gtk.main()
   177       return 0
   178   
   179   if __name__ == "__main__":
   180       ExempleZoneDessin()
   181       main()