Passons au processus de dessin sur l'écran. Le widget que l'on
utilise pour ceci est le widget DrawingArea
(voir le
Chapitre 12, La zone de dessin (Drawing Area)). Un tel widget est essentiellement une
fenêtre X et rien de plus. Il s'agit d'une toile vide sur laquelle nous pouvons
dessiner ce que nous voulons. On créé ce widget par l'appel à :
darea = gtk.DrawingArea()
On peut lui donner Une taille par défaut par l'appel :
darea.set_size_request(largeur
,hauteur
)
Cette taille par défaut peu être surchargée, comme pour tous les widgets,
en appelant la méthode set_size_request
() et celle-ci,
à son tour, peut être surchargée si l'utilisateur modifie manuellement la taille
de la fenêtre contenant la zone de dessin.
Il faut noter que lorsque l'on crée un widget
DrawingArea
, on est complètement responsable du dessin
du contenu. Si la fenêtre est cachée puis redécouverte, on reçoit un événement
d'exposition et on doit redessiner ce qui avait été caché auparavant.
Devoir se rappeler tout ce qui a été dessiné à l'écran pour pouvoir correctement le redessiner peut s'avérer, et c'est un euphémisme, pénible. De plus, cela peut être visible si des portions de la fenêtre sont effacées puis redessinées étape par étape. La solution à ce problème est d'utiliser un pixmap d'arrière-plan hors écran. Au lieu de dessiner directement sur l'écran, on dessine sur une image stockée dans la mémoire du serveur et non affichée, puis, lorsque l'image change ou lorsque de nouvelles parties de l'image sont affichées, on copie les parties correspndantes sur l'écran.
Pour créer un pixmap hors écran, on appelle la fonction :
pixmap = gtk.gdk.Pixmap(fenetre
,largeur
,hauteur
,profondeur
=-1)
Le paramètre fenetre
désigne une fenêtre
gtk.gdk.Window
d'où ce pixmap tire certaines de ses
propriétés. Les paramètres largeur
et
hauteur
précisent la taille du pixmap, profondeur
précise la profondeur de couleur (c'est-à-dire le nombre de bits par pixel)
de la nouvelle fenêtre. Si cette profondeur
vaut -1 ou
n'est pas indiquée, elle correspondra à celle de fenetre
.
On crée le pixmap dans notre gestionnaire "configure_event". Cet événement est généré à chaque fois que la fenêtre change de taille, y compris lors de sa création initiale.
32 # Création d'un nouveau pixmap d'arrière-plan de la taille voulue 33 def configure_event(widget, event): 34 global pixmap 35 36 x, y, largeur, hauteur = widget.get_allocation() 37 pixmap = gtk.gdk.Pixmap(widget.window, largeur, hauteur) 38 pixmap.draw_rectangle(widget.get_style().white_gc, 39 True, 0, 0, largeur, hauteur) 40 41 return True
L'appel à draw_rectangle
() initialise le pixmap
à blanc. Nous en dirons plus tout à l'heure.
Le gestionnaire d'événement d'exposition copie alors simplement la
partie utile du pixmap sur la zone de dessin (widget) en utilisant la
méthode draw_pixmap
(). On détermine la zone
à redessiner en utilisant l'attribut event.area
de
l'événement d'exposition) :
43 # Redessine l'écran à partir du pixmap d'arrière-plan 44 def expose_event(widget, event): 45 x , y, largeur, hauteur = event.area 46 widget.window.draw_drawable(widget.get_style().fg_gc[gtk.STATE_NORMAL], 47 pixmap, x, y, x, y, largeur, hauteur) 48 return False
On a vu comment garder l'écran à jour avec notre pixmap, mais
comment dessine-t-on réellement ce que l'on veut dans le pixmap ? Il existe
un grand nombre d'appels dans PyGTK pour dessiner sur des dessinables. Un
dessinable est simplement quelque chose sur lequel on peut dessiner. Cela peut
être une fenêtre, un pixmap, ou un bitmap (une image en noir et blanc). On a déjà
vu plus haut deux de ces appels, draw_rectangle
() et
draw_pixmap
(). En voici La liste complète :
drawable.draw_point(gc
,x
,y
) drawable.draw_line(gc
,x1
,y1
,x2
,y2
) drawable.draw_rectangle(gc
,fill
,x
,y
,width
,height
) drawable.draw_arc(gc
,fill
,x
,y
,width
,height
,angle1
,angle2
) drawable.draw_polygon(gc
,fill
,points
) drawable.draw_drawable(gc
,src
,xsrc
,ysrc
,xdest
,ydest
,width
,height
) drawable.draw_points(gc
,points
) drawable.draw_lines(gc
,points
) drawable.draw_segments(gc
,segments
) drawable.draw_rgb_image(gc
,x
,y
,width
,height
,dither
,buffer
,rowstride
) drawable.draw_rgb_32_image(gc
,x
,y
,width
,height
,dither
,buffer
,rowstride
) drawable.draw_gray_image(gc
,x
,y
,width
,height
,dither
,buffer
,rowstride
)
Les méthodes des zones de dessin sont identiques à celles des
dessinables, ainsi on peut se reporter aux méthodes décrites dans la
Section 12.2, « Les méthodes pour dessiner » pour plus de détails sur celles-ci.
Toutes ces méthodes partagent les mêmes premiers arguments, le premier étant
le contexte graphique (gc
).
Un contexte graphique encapsule l'information sur des éléments
comme la couleur de premier et d'arrière plan et la largeur de ligne. PyGTK
possède un ensemble complet de fonctions pour créer et manipuler les contextes
graphiques, mais, pour faire simple, nous n'utiliserons que les contextes graphiques
prédéfinis. Reportez-vous à la Section 12.1, « Le contexte graphique » pour
plus d'informations sur les contextes graphiques. Chaque widget posséde un style
associé (qui peut être modifié dans un fichier gtkrc
, voir la
Chapitre 23, Les fichiers de style rc GTK. Celui-ci, entre autres choses, stocke plusieurs
contextes graphiques. Quelques exemples d'accès à ces contextes graphiques :
widget.get_style().white_gc widget.get_style().black_gc widget.get_style().fg_gc[STATE_NORMAL] widget.get_style().bg_gc[STATE_PRELIGHT]
Les champs fg_gc
, bg_gc
,
dark_gc
et light_gc
sont indexés par
un paramètre qui peut prendre les valeurs suivantes :
STATE_NORMAL, STATE_ACTIVE, STATE_PRELIGHT, STATE_SELECTED, STATE_INSENSITIVE
Par exemple, pour STATE_SELECTED
, la couleur de premier
plan par défaut est blanc, la couleur d'arrière plan par défaut est bleu foncé.
La fonction draw_brush
(), qui réalise le dessin
sur le pixmap est alors :
50 # Dessine un rectangle sur l'écran 51 def brosse_dessin(widget, x, y): 52 rect = (int(x-5), int(y-5), 10, 10) 53 pixmap.draw_rectangle(widget.get_style().black_gc, True, 54 rect[0], rect[1], rect[2], rect[3]) 55 widget.queue_draw_area(rect[0], rect[1], rect[2], rect[3])
Après avoir dessiné le rectangle représentant la brosse sur le pixmap, on appelle la fonction :
widget.queue_draw_area(x
,y
,width
,height
)
... qui indique à X que cette zone nécessite d'être mise à jour.
X génèrera éventuellement un événement d'exposition (en combinant peut-être les
zones passés dans plusieurs appels à draw
()) ce qui
forcera le gestionnaire d'événement d'exposition à recopier les parties adéquates
à l'écran.
Nous avons maintenant couvert entièrement le programme de dessin, sauf quelques détails banals comme la création de la fenêtre principale.