4. Chapitre 4. Le placement des widgets▲
Pour créer une application, on aura la plupart du temps, besoin de mettre plusieurs widgets dans la même fenêtre. Notre premier exemple de programme (helloworld.py) n'utilisait qu'un seul widget, nous pouvions donc simplement l'ajouter à la fenêtre avec la méthode de GtkContainer add(). Mais si l'on souhaite mettre plusieurs widgets dans un fenêtre, comment contrôle-t-on la manière dont ils sont placés ? C'est ce que nous allons développer dans ce chapitre.
4-1. Le principe des boîtes de placement▲
Le placement des widgets passe la plupart du temps par la création de boîtes. Il s'agit de conteneurs invisibles dans lesquels on peut placer nos widgets, et qui existent sous deux formes : la boîte horizontale et la boîte verticale. Lorsque l'on place des widgets dans une boîte horizontale, ceux-ci sont insérés horizontalement, de gauche à droite ou de droite à gauche en fonction de l'appel utilisé. Dans une boîte verticale, les widgets sont placés de haut en bas ou inversement. Vous pouvez utiliser toutes les combinaisons de boîtes que vous voulez à l'intérieur ou à l'extérieur d'autres boîtes pour obtenir l'effet recherché.
Pour créer une boîte horizontale, on fait appel à gtk.HBox(), et pour une boîte verticale, à gtk.VBox(). Pour placer des objets dans ces conteneurs, on utilise les méthodes pack_start() et pack_end(). La première les place de haut en bas dans une VBox et de gauche à droite dans une HBox. La seconde fait le contraire : de bas en haut dans une VBox et de droite à gauche dans une HBox. Ces méthodes nous permettent d'aligner nos widgets à gauche ou à droite, et d'obtenir exactement l'effet désiré en les alternant. Nous utiliserons pack_start() dans la majeure partie de nos exemples. Les objets placés à l'intérieur des boîtes peuvent être des widgets ou de nouveaux conteneurs. En fait, beaucoup de widgets sont déjà eux-mêmes des conteneurs, y compris le bouton (mais on n'utilise généralement qu'une étiquette à l'intérieur d'un bouton).
Grâce à ces appels et à leurs options, GTK sait exactement où et de quelle manière vous voulez placer vos widgets dans le conteneur. De leur définition dépendent de nombreux paramètres comme, par exemple, le redimensionnement automatique. Ces méthodes nous offrent une grande flexibilité dans le placement et la création de nos widgets.
4-2. Les boîtes en détail▲
Du fait même de cette flexibilité, les boîtes de placement peuvent paraître un peu déroutantes au début. Il y a beaucoup d'options et il n'est pas toujours évident de comprendre leurs effets. Mais en somme, on peut dire qu'il y a cinq styles différents. La figure 4.1 montre ce qu'on obtient en lançant le programme boites.py avec l'argument 1 :
Chaque ligne contient une boîte horizontale comportant plusieurs boutons. L'appel de placement que vous pouvez y lire est un abregé de celui utilisé pour placer chacun des boutons de la ligne. Tous les boutons d'un même HBox sont placés de la même manière (mêmes arguments pour la méthode pack_start()).
Voici comment s'utilise la méthode pack_start().
boite.pack_start
(
child, expand, fill, padding)
boite est la boîte dans laquelle vous allez placer l'objet child (enfant). Pour le moment, les objets seront des boutons. Nous allons donc voir comment placer des boutons dans des boîtes.
L'argument expand de pack_start() et pack_end() contrôle si les widgets doivent occuper tout l'espace disponible dans la boîte (TRUE) — celle-ci s'étirera alors pour remplir la zone qui lui est allouée —, ou si la boîte doit au contraire rétrécir jusqu'à la taille minimale nécessaire aux widgets (FALSE). Régler expand sur FALSE vous permettra d'aligner tous vos widgets à droite ou à gauche. Autrement, ils s'étaleront pour occuper tout l'espace de la boîte. Le même effet pourrait être obtenu en utilisant uniquement une des deux fonctions pack_start() ou pack_end().
Grâce à l'argument fill, on peut ordonner que l'espace vide autour des widgets leur soit alloué (TRUE). Sinon, on ne touche à rien (FALSE), cet espace jouera le rôle d'un padding supplémentaire autour des objets. fill n'a d'effet que si expand vaut TRUE.
Les fonctions ou méthodes que nous découvrirons tout au long de ce tutoriel peuvent comporter, grâce à Python, des mots-clés et des valeurs par défaut. Le cas échéant, nous les mentionnerons dans la définition de leur fonction, comme à présent avec les méthodes pack_start() et pack_end() :
2.
3.
boite.pack_start
(
child, expand=
True
, fill=
True
, padding=
0
)
boite.pack_end
(
child, expand=
True
, fill=
True
, padding=
0
)
child, expand, fill et padding sont des mots-clés (ils apparaitront toujours en gras). On peut remarquer les valeurs par défaut des arguments expand, fill et padding. L'argument child, quant à lui, devra obligatoirement être spécifié.
La création d'une boîte ressemble à ceci :
2.
3.
boite_h =
gtk.HBox
(
homogeneous=
gtk.FALSE, spacing=
0
)
boite_v =
gtk.VBox
(
homogeneous=
gtk.FALSE, spacing=
0
)
L'argument homogeneous (homogène) de gtk.HBox() et gtk.VBox() attribue ou pas la même taille à chaque objet dans la boîte (la même largeur dans une HBox, ou la même hauteur dans une VBox). S'il vaut TRUE, on obtiendra à peu de choses près le même effet qu'en activant l'argument expand pour chaque objet.
Quelle est la différence entre spacing (défini lors de la création d'une boîte) et padding (défini lors du placement d'un objet), qui fixent tous les deux un espacement ? spacing ajoute de l'espace entre les objets, et padding de chaque côté d'un objet. La figure 4.2 illustre cette différence en passant l'argument 2 à boites.py :
La figure 4.3 montre l'utilisation de la méthode pack_end() (passez 3 comme argument à boites.py). L'étiquette "fin" est placée avec cette méthode. Elle colle à l'extrémité droite de la fenêtre, même en cas de redimensionnement.
4-3. Démonstration de placement avec les boîtes▲
Voici le code qui a généré les images de la section précédente. Il est assez abondamment commenté, aussi j'espère que vous n'aurez pas de problème à le suivre. Lancez-le et modifiez-le à souhait.
En route pour une brève visite guidée du code :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
217.
218.
219.
220.
221.
222.
223.
224.
225.
226.
227.
228.
229.
230.
231.
232.
233.
234.
235.
236.
237.
238.
239.
240.
241.
242.
243.
244.
245.
246.
247.
248.
249.
250.
251.
252.
253.
254.
#
!/usr/bin/env
python
#
exemple
boite.py
import
pygtk
pygtk.require
(
'
2
.
0
'
)
import
gtk
import
sys, string
#
Cette
fonction
nous
aide
a
créer
une
nouvelle
HBox
remplie
de
boutons+étiquettes.
#
Des
arguments
pour
les
variables
qui
nous
intéressent
lui
sont
transmis.
On
n'affiche
#
pas
la
boîte
(avec
show()),
mais
on
affiche
tout
ce
qui
se
trouve
a
l'intérieur.
def
creer_boite
(
homogeneous, spacing, expand, fill, padding):
#
On
crée
une
nouvelle
boite
avec
les
valeurs
#
transmises
pour
"homogeneous"
et
"spacing"
boite =
gtk.HBox
(
homogeneous, spacing)
#
On
crée
une
série
de
boutons,
toujours
avec
les
valeurs
transmises.
bouton =
gtk.Button
(
"
boite
.
pack
"
)
boite.pack_start
(
bouton, expand, fill, padding)
bouton.show
(
)
bouton =
gtk.Button
(
"
(
bouton
,
"
)
boite.pack_start
(
bouton, expand, fill, padding)
bouton.show
(
)
#
On
crée
un
bouton
dont
l'étiquette
dépendra
de
la
valeur
#
de
"expand".
if
expand =
=
True
:
bouton =
gtk.Button
(
"
True
,
"
)
else
:
bouton =
gtk.Button
(
"
False
,
"
)
boite.pack_start
(
bouton, expand, fill, padding)
bouton.show
(
)
#
Même
principe
que
ci-dessus,
mais
cette
fois
avec
la
#
formulation
abrégée
bouton =
gtk.Button
(
(
"
False
,
"
, "
True
,
"
)[fill=
=
True
])
boite.pack_start
(
bouton, expand, fill, padding)
bouton.show
(
)
chaine_pad =
"
%d
)
"
%
padding
bouton =
gtk.Button
(
chaine_pad)
boite.pack_start
(
bouton, expand, fill, padding)
bouton.show
(
)
return
boite
class
BoitesPLacement:
def
evnmt_delete
(
self, widget, evenement, donnees=
None
):
gtk.main_quit
(
)
return
False
def
__init__
(
self, numero):
#
Création
de
notre
fenêtre
self.fenetre =
gtk.Window
(
gtk.WINDOW_TOPLEVEL)
#
N'oubliez
pas
de
connecter
le
signal
"delete_event"
#
a
la
fenêtre
principale.
Cela
donne
au
programme
#
un
comportement
plus
intuitif.
self.fenetre.connect
(
"
delete_event
"
, self.evnmt_delete)
self.fenetre.set_border_width
(
10
)
#
On
crée
une
boîte
verticale
(VBox)
pour
y
placer
nos
boîtes
#
horizontales.
Ainsi
on
peut
empiler
les
boîtes
horizontales
#
remplies
de
boutons
les
unes
sur
les
autres
dans
la
VBox.
boite1 =
gtk.VBox
(
False
, 0
)
#
Sur
quel
scenario
partons-nous
?
(cf.
images
de
la
section
4.2)
if
numero =
=
1
:
#
Création
d'une
nouvelle
etiquette.
etiquette =
gtk.Label
(
"
HBox
(
False
,
0
)
"
)
#
On
aligne
l'étiquette
à
gauche.
Nous
verrons
cette
méthode
#
ainsi
que
d'autres
dans
la
section
sur
les
attributs
des
widgets.
etiquette.set_alignment
(
0
, 0
)
#
On
place
l'étiquette
dans
la
boîte
verticale
(la
VBox
boite1).
#
Souvenez-vous
que
les
widgets
ajoutés
à
une
VBox
seront
placés
#
les
uns
sur
les
autres,
dans
l'ordre.
boite1.pack_start
(
etiquette, False
, False
, 0
)
#
On
affiche
l'étiquette.
etiquette.show
(
)
#
On
appelle
notre
fonction
creer_boite
en
lui
transmettant
:
#
homogeneous=False,
spacing=0,
expand=False,
fill=False,
padding=0
boite2 =
creer_boite
(
False
, 0
, False
, False
, 0
)
boite1.pack_start
(
boite2, False
, False
, 0
)
boite2.show
(
)
#
On
appelle
notre
fonction
creer_boite
en
lui
transmettant
:
#
homogeneous=False,
spacing=0,
expand=True,
fill=False,
padding=0
boite2 =
creer_boite
(
False
, 0
, True
, False
, 0
)
boite1.pack_start
(
boite2, False
, False
, 0
)
boite2.show
(
)
#
homogeneous=False,
spacing=0,
expand=True,
fill=True,
padding=0
boite2 =
creer_boite
(
False
, 0
, True
, True
, 0
)
boite1.pack_start
(
boite2, False
, False
, 0
)
boite2.show
(
)
#
Création
d'un
séparateur.
On
en
apprendra
plus
sur
ce
widget
#
ultérieurement
mais
il
est
assez
simple.
separateur =
gtk.HSeparator
(
)
#
On
place
le
séparateur
dans
la
VBox.
Gardez
bien
à
l'esprit
que
#
tout
ces
widgets
sont
placés
dans
une
VBox,
ils
sont
donc
#
empilés
les
uns
sur
les
autres.
boite1.pack_start
(
separateur, False
, True
, 5
)
separateur.show
(
)
#
On
crée
une
autre
étiquette,
et
on
l'affiche.
etiquette =
gtk.Label
(
"
HBox
(
True
,
0
)
"
)
etiquette.set_alignment
(
0
, 0
)
boite1.pack_start
(
etiquette, False
, False
, 0
)
etiquette.show
(
)
#
homogeneous=True,
spacing=0,
expand=True,
fill=False,
padding=0
boite2 =
creer_boite
(
True
, 0
, True
, False
, 0
)
boite1.pack_start
(
boite2, False
, False
, 0
)
boite2.show
(
)
#
homogeneous=True,
spacing=0,
expand=True,
fill=True,
padding=0
boite2 =
creer_boite
(
True
, 0
, True
, True
, 0
)
boite1.pack_start
(
boite2, False
, False
, 0
)
boite2.show
(
)
#
Un
autre
separateur.
separateur =
gtk.HSeparator
(
)
#
Les
trois
derniers
arguments
de
pack_start()
sont
:
#
expand,
fill,
padding.
boite1.pack_start
(
separateur, False
, True
, 5
)
separateur.show
(
)
elif
numero =
=
2
:
#
On
crée
une
étiquette,
souvenez-vous
que
boite1
est
une
VBox,
#
créée
vers
le
début
de
__init__()
etiquette =
gtk.Label
(
"
HBox
(
False
,
10
)
"
)
etiquette.set_alignment
(
0
, 0
)
boite1.pack_start
(
etiquette, False
, False
, 0
)
etiquette.show
(
)
#
homogeneous=False,
spacing=10,
expand=True,
fill=False,
padding=0
boite2 =
creer_boite
(
False
, 10
, True
, False
, 0
)
boite1.pack_start
(
boite2, False
, False
, 0
)
boite2.show
(
)
#
homogeneous=False,
spacing=10,
expand=True,
fill=True,
padding=0
boite2 =
creer_boite
(
False
, 10
, True
, True
, 0
)
boite1.pack_start
(
boite2, False
, False
, 0
)
boite2.show
(
)
separateur =
gtk.HSeparator
(
)
#
Les
trois
derniers
arguments
de
pack_start()
sont
:
#
expand,
fill,
padding.
boite1.pack_start
(
separateur, False
, True
, 5
)
separateur.show
(
)
etiquette =
gtk.Label
(
"
HBox
(
False
,
0
)
"
)
etiquette.set_alignment
(
0
, 0
)
boite1.pack_start
(
etiquette, False
, False
, 0
)
etiquette.show
(
)
#
homogeneous=False,
spacing=0,
expand=True,
fill=False,
padding=10
boite2 =
creer_boite
(
False
, 0
, True
, False
, 10
)
boite1.pack_start
(
boite2, False
, False
, 0
)
boite2.show
(
)
#
homogeneous=False,
spacing=0,
expand=True,
fill=True,
padding=10
boite2 =
creer_boite
(
False
, 0
, True
, True
, 10
)
boite1.pack_start
(
boite2, False
, False
, 0
)
boite2.show
(
)
separateur =
gtk.HSeparator
(
)
#
Les
trois
derniers
arguments
de
pack_start()
sont
:
#
expand,
fill,
padding.
boite1.pack_start
(
separateur, False
, True
, 5
)
separateur.show
(
)
elif
numero =
=
3
:
#
Ce
scenario
est
la
pour
montrer
qu'avec
pack_end()
on
peut
aligner
#
les
widgets
à
droite.
D'abord,
créons
une
boîte,
comme
avant.
boite2 =
creer_boite
(
False
, 0
, False
, False
, 0
)
#
on
crée
l'étiquette
que
l'on
alignera
à
droite.
etiquette =
gtk.Label
(
"
fin
"
)
#
On
la
place
avec
pack_end(),
elle
va
se
placer
à
l'extrémité
#
droite
de
la
HBox
créée
par
l'appel
à
creer_boite().
boite2.pack_end
(
etiquette, False
, False
, 0
)
#
On
affiche
l'étiquette.
etiquette.show
(
)
#
On
place
boite2
dans
boite1
boite1.pack_start
(
boite2, False
, False
, 0
)
boite2.show
(
)
#
Un
séparateur
pour
le
bas.
separateur =
gtk.HSeparator
(
)
#
Cette
méthode
fixe
les
dimensions
du
séparateur
(400
pixels
de
large
#
pour
5
pixels
de
haut).
C'est
pour
que
la
HBox
qu'on
vient
de
créer
#
fasse
aussi
400
de
large,
et
que
l'étiquette
"fin"
soit
bien
séparée
#
des
autres
widgets
de
la
HBox.
Autrement,
tous
les
widgets
de
la
#
HBox
seraient
placés
aussi
près
l'un
de
l'autre
que
possible.
separateur.set_size_request
(
400
, 5
)
#
On
place
le
séparateur
dans
la
HBox
(boite1)
créée
vers
le
début
#
de
__init__()
boite1.pack_start
(
separateur, False
, True
, 5
)
separateur.show
(
)
#
On
crée
une
autre
HBox.
On
peut
en
utiliser
autant
qu'on
veut
!
boitequitter =
gtk.HBox
(
False
, 0
)
#
Notre
bouton
"Quitter".
bouton =
gtk.Button
(
"
Quitter
"
)
#
Lorsque
l'on
clique
sur
le
bouton,
le
signal
émis
doit
terminer
le
programme.
bouton.connect_object
(
"
clicked
"
, gtk.main_quit, self.fenetre)
#
On
place
le
bouton
dans
la
HBox
boitequitter.
#
Les
trois
derniers
arguments
de
pack_start()
sont
:
#
expand,
fill,
padding.
boitequitter.pack_start
(
bouton, True
, False
, 0
)
#
On
place
boitequitter
dans
la
VBox
(boite1)
boite1.pack_start
(
boitequitter, False
, False
, 0
)
#
On
place
la
VBox
boite1
(qui
contient
maintenant
tous
nos
widgets)
#
dans
la
fenêtre
principale.
self.fenetre.add
(
boite1)
#
Et
on
affiche
ce
qu'il
reste
à
afficher.
bouton.show
(
)
boitequitter.show
(
)
boite1.show
(
)
#
La
fenêtre
en
dernier,
afin
que
tout
s'affiche
d'un
coup.
self.fenetre.show
(
)
def
main
(
):
#
Et
bien
sûr,
notre
boucle
principale.
gtk.main
(
)
#
Le
contrôle
revient
ici
lorsque
main_quit()
est
appelée.
return
0
if
__name__
=
=
"
__main__
"
:
if
len(
sys.argv) !
=
2
:
sys.stderr.write
(
"
La
commande
doit
être
de
la
forme
\"
boite
.
py
num
\"
,
avec
num
=
1
ou
2
ou
3
\n
"
)
sys.exit
(
1
)
BoitesPLacement
(
string.atoi
(
sys.argv[1
]))
main
(
)
De la ligne 14 à la ligne 50, on définit une fonction creer_boite() qui nous facilitera la création des boîtes horizontales. À chaque appel, elle créera une HBox et la remplira de cinq boutons en respectant les paramètres spécifiés. Sa valeur de retour est une référence à elle-même.
Puis on définit le constructeur __init__() de la classe BoitesPLacement (lignes 52 à 241), qui crée une fenêtre et une boîte verticale enfant. Cette dernière contiendra d'autre widgets dont la nature et la disposition dépendent de l'argument qu'elle reçoit. Si elle reçoit 1, elle crée une fenêtre montrant les cinq arrangements de widgets que l'on peut obtenir en jouant sur les paramètres homogeneous , expand et fill (lignes 75 à 138). Si elle reçoit 2, elle crée une fenêtre qui affiche cette fois-ci les différentes combinaisons de remplissage offertes par les paramètres spacing et padding (lignes 140 à 182). Enfin, en recevant 3, la fenêtre créée par la fonction montrera l'utilisation des méthodes pack_start() et pack_end(), la première pour aligner les boutons à gauche et la seconde pour aligner une étiquette à droite (lignes 188 à 214). Aux lignes 215 à 235, on crée une boîte horizontale contenant un bouton, et on la place dans la boîte verticale. Le signal "clicked" du bouton est connecté à la fonction PyGTK main_quit() pour terminer le programme.
Aux lignes 250 à 252, on vérifie la ligne de commande : celle-ci doit comporter un seul argument. Dans le cas contraire, on sort du programme avec la fonction sys.exit(). La ligne 253 crée une instance de BoitesPLacement et la ligne 254 invoque la fonction main() qui va initialiser la boucle du réceptionnaire d'évènements de GTK.
Dans ce programme exemple, aucune référence de widget n'est enregistrée dans un attribut d'instance (sauf pour la fenêtre). En effet, nos widgets ne seront plus sollicités après leur création.
4-4. Le placement avec les tableaux▲
Intéressons-nous à présent à un autre moyen de placer les widgets, qui peut se révéler extrêmement utiles dans certaines occasions : les tableaux.
Avec les tableaux, on crée une grille dans laquelle on peut placer des widgets. Ces derniers peuvent occuper autant d'espace que nous le voulons.
Examinons tout d'abord la fonction gtk.Table() :
tableau =
gtk.Table
(
rows=
1
, columns=
1
, homogeneous=
FALSE)
Le premier argument est le nombre de lignes (rows) souhaitées dans le tableau et le deuxième le nombre de colonnes (columns).
L'argument homogeneous concerne l'homogénéité ou pas des cellules du tableau. S'il vaut TRUE, les cellules feront toutes la même taille : celle du plus grand widget dans le tableau. S'il vaut FALSE, la largeur d'une cellule sera dictée par le widget le plus large de la colonne, et sa hauteur par le widget le plus haut de la ligne.
Les lignes et les colonnes sont numérotées de 0 à n, n étant le nombre spécifié lors de l'appel à gtk.Table(). Donc, en donnant rows=2 et columns=2, on obtient un tableau qui peut être schématisé ainsi :
2.
3.
4.
5.
6.
1
2
0
+
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
+
|
|
|
1
+
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
+
|
|
|
2
+
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
+
Notez que le système de coordonnées commence dans le coin supérieur gauche. Pour placer un widget dans une cellule, on utilisera la méthode suivante :
tableau.attach
(
child, left_attach, right_attach, top_attach, bottom_attach,
xoptions=
EXPAND|
FILL, yoptions=
EXPAND|
FILL, xpadding=
0
, ypadding=
0
)
L'instance tableau est le tableau créé avec gtk.Table(). Le premier paramètre, child (enfant), est le widget que vous souhaitez placer dans le tableau.
Les arguments left_attach (point d'attache gauche), right_attach (point d'attache droit), top_attach (point d'attache haut) et bottom_attach (point d'attache bas) indiquent où placer le widget et combien de cellules il doit occuper. Si l'on veut mettre un bouton dans la cellule inférieure droite de notre tableau 2x2, et s'il ne doit occuper QUE cette cellule, il faudra donner à ces arguments les valeurs suivantes : left_attach = 1, right_attach = 2, top_attach = 1, bottom_attach = 2.
Maintenant, si l'on veut qu'un widget occupe toute la première ligne de notre tableau 2x2, on doit donner left_attach = 0, right_attach = 2, top_attach = 0, bottom_attach = 1.
Les paramètres xoptions et yoptions servent à spécifier une ou plusieurs (avec un OU logique) options de placement.
Ces options sont :
FILL |
Si la cellule est plus large que le widget et que FILL est spécifié, le widget s'étirera jusqu'à occuper tout l'espace disponible dans la cellule. |
SHRINK |
Quand le tableau ne dispose pas de suffisamment d'espace pour afficher les widgets (par exemple, lors d'un redimensionnement de la fenêtre par l'utilisateur), ces derniers sont normalement éjectés vers le bas de la fenêtre et disparaissent. Si SHRINK est spécifié, les widgets rétréciront avec le tableau. |
EXPAND |
Si cette option est spécifiée, la cellule s'étirera jusqu'à occuper toute la place restant dans l'espace attribué au tableau. |
Comme pour les boîtes de placement, les paramètres de padding créent une zone vide, spécifiée en pixels, autour du widget.
Deux autres méthodes, set_row_spacing() et set_col_spacing(), nous permettent de définir des espacements entre des lignes ou des colonnes :
tableau.set_row_spacing
(
row, spacing)
et
tableau.set_col_spacing
(
column, spacing)
Pour les colonnes (column), l'espacement (spacing) sera appliqué à la droite de la colonne spécifiée ; pour les lignes (rows) ce sera au dessous de la ligne spécifiée.
On peut aussi fixer en une fois un même espacement pour toutes les lignes et/ou colonnes du tableau :
tableau.set_row_spacings
(
spacing)
et
tableau.set_col_spacings
(
spacing)
Notez qu'avec ces appels la dernière ligne et la dernière colonne ne reçoivent aucun espacement.
4-5. Démonstration de placement avec les tableaux▲
Le programme exemple tableaux.py crée une fenêtre avec trois boutons dans un tableau de 2x2. Les deux premiers boutons sont placés sur la ligne du haut. Le troisième, le bouton "Quitter", est placé sur la ligne du bas et occupe les deux colonnes. La figure 4.4 montre la fenêtre obtenue :
Voici le code source :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
#
!/usr/bin/env
python
#
exemple
tableau.py
import
pygtk
pygtk.require
(
'
2
.
0
'
)
import
gtk
class
Tableau:
#
Notre
fonction
de
rappel.
Le
paramètre
"donnees"
#
transmis
a
cette
méthode
est
affiché
sur
stdout
def
salut
(
self, widget, donnees=
None
):
print
"
Salut
!
-
Clic
sur
le
%s
.
"
%
donnees
#
Cette
fonction
de
rappel
quitte
le
programme
def
evnmt_delete
(
self, widget, evenement, donnees=
None
):
gtk.main_quit
(
)
return
False
def
__init__
(
self):
#
Création
d'une
nouvelle
fenetre.
self.fenetre =
gtk.Window
(
gtk.WINDOW_TOPLEVEL)
#
On
définit
le
titre
de
la
fenetre.
self.fenetre.set_title
(
"
Tableau
"
)
#
On
définit
un
gestionnaire
de
signal
pour
"delete_event",
#
qui
quitte
GTK
immédiatement.
self.fenetre.connect
(
"
delete_event
"
, self.evnmt_delete)
#
On
fixe
la
largeur
des
bordures
de
la
fenêtre.
self.fenetre.set_border_width
(
20
)
#
Création
d'un
tableau
de
2x2.
tableau =
gtk.Table
(
2
, 2
, True
)
#
On
place
le
tableau
dans
la
fenêtre
principale.
self.fenetre.add
(
tableau)
#
Création
du
premier
bouton.
bouton =
gtk.Button
(
"
bouton
1
"
)
#
Lorsque
l'on
clique
sur
le
bouton,
la
méthode
salut()
est
#
appelée,
avec
un
pointeur
sur
"bouton
1"
comme
argument.
bouton.connect
(
"
clicked
"
, self.salut, "
bouton
1
"
)
#
Insertion
du
bouton
1
dans
le
quart
supérieur
gauche
du
tableau.
tableau.attach
(
bouton, 0
, 1
, 0
, 1
)
bouton.show
(
)
#
Création
du
second
bouton.
bouton =
gtk.Button
(
"
bouton
2
"
)
#
Lorsque
l'on
clique
sur
le
bouton,
la
méthode
"salut"
est
#
appelée,
avec
un
pointeur
sur
"bouton
2"
comme
argument.
bouton.connect
(
"
clicked
"
, self.salut, "
bouton
2
"
)
#
Insertion
du
bouton
2
dans
le
quart
supérieur
droit
du
tableau.
tableau.attach
(
bouton, 1
, 2
, 0
, 1
)
bouton.show
(
)
#
Création
du
bouton
"Quitter".
bouton =
gtk.Button
(
"
Quitter
"
)
#
Lorsque
l'on
clique
sur
le
bouton,
la
fonction
mainquit
est
#
appelée
et
le
programme
se
termine.
bouton.connect
(
"
clicked
"
, gtk.main_quit)
#
Insertion
du
bouton
"Quitter"
dans
les
deux
quarts
inférieurs
du
tableau.
tableau.attach
(
bouton, 0
, 2
, 1
, 2
)
bouton.show
(
)
tableau.show
(
)
self.fenetre.show
(
)
def
main
(
):
gtk.main
(
)
return
0
if
__name__
=
=
"
__main__
"
:
Tableau
(
)
main
(
)
La classe Tableau est définie de la ligne 9 à la ligne 78.
Aux lignes 12-13, on définit la fonction de rappel salut(), appelée par un clic sur le bouton 1 ou sur le bouton 2. Elle affiche juste un message dans la console qui indique quel bouton a été cliqué, et se sert pour cela de la chaîne de caractères qui lui est transmise.
Aux lignes 16-18, on définit la méthode evnmt_delete(), qui est invoquée lorsque le gestionnaire de fenêtres tente de fermer la fenêtre principale.
De la ligne 20 à la ligne 78, on définit __init__(), la méthode constructeur de la classe Tableau. Elle crée une fenêtre (ligne 22), lui donne un titre (ligne 25), connecte la fonction de rappel evnmt_delete() au signal "delete_event" (ligne 29), et fixe les bordures de la fenêtre (ligne 32). Un gtk.Table est créé à la ligne 35 et est ajouté à la fenêtre principale à la ligne 38.
Puis les deux boutons du haut sont créés (lignes 41 et 55), on connecte leurs signaux "clicked" à la méthode salut() (lignes 45 et 59) et on les place dans la première ligne du tableau (lignes 49 et 61). Pour finir, on crée le bouton "Quitter" aux lignes 66 à 73, on connecte son signal "clicked" à la fonction mainquit(), et on le place sur toute l'étendue de la seconde ligne du tableau.