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.
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 :
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()