9. Chapitre 9. Widgets divers▲
9-1. Les étiquettes▲
Les étiquettes (gtk.Label) sont des widgets relativement simples et très utilisés dans GTK. Elles ne peuvent émettre aucun signal, car elles n'ont pas de fenêtres X associées. Pour capter quand même des signaux ou pour ce qui concerne le découpage, il vous faudra les placer dans des boites à évènementsLa boîte à évènement (EventBox) ou dans des boutons (voir Boutons simplesLes boutons simples).
Pour créer une étiquette, on utilise la méthode suivante :
etiquette =
gtk.Label
(
str)
L'unique argument à fournir, str, est la chaîne de caractères que doit afficher l'étiquette. Pour changer ce texte une fois l'étiquette créée, on fera appel à la méthode :
etiquette.set_text
(
str)
etiquette est l'étiquette précédemment créée, et str la nouvelle chaîne de caractères. L'espace alloué à la nouvelle chaîne sera automatiquement ajusté si nécessaire. Vous pouvez créer une étiquette de plusieurs lignes en insérant des sauts de lignes dans la chaîne de caractères.
Pour récupérer la chaîne courante, faites :
chaine =
etiquette.get_text
(
)
etiquette est l'étiquette que vous avez créée, et chaine la chaîne de caractères. On peut définir le type d'alignement du texte d'une étiquette avec :
etiquette.set_justify
(
jtype)
L'argument jtype peut prendre les valeurs suivantes :
2.
3.
4.
JUSTIFY_LEFT #
aligné
à
gauche
JUSTIFY_RIGHT #
aligné
à
droite
JUSTIFY_CENTER #
centré
(valeur
par
défaut)
JUSTIFY_FILL #
justifié
Le texte des étiquettes peut aussi être renvoyé à la ligne automatiquement. Il faut pour cela utiliser cette méthode :
etiquette.set_line_wrap
(
wrap)
L'argument wrap peut prendre les valeurs TRUE (activé) ou FALSE (désactivé).
Pour que le texte de votre étiquette soit souligné, vous pouvez lui fournir un patron à suivre :
etiquette.set_pattern
(
pattern)
L'argument pattern (patron) précise le profil du soulignement. Il s'agit d'une chaîne de caractères constituée de "_" et d'espaces, un "_" indiquant que le caractère correspondant de l'étiquette doit être souligné. Par exemple, la chaîne "__ __" soulignerait les deux premiers caractères ainsi que le huitième et le neuvième. Si vous voulez simplement définir un raccourci clavier souligné (un caractère "mnémonique") dans votre étiquette, utilisez plutôt la méthode set_text_with_mnemonic (str), et non set_pattern().
Le programme etiquettes.py est un court exemple qui illustre ces méthodes. Pour mieux distinguer les différents styles d'étiquettes, il utilise des cadres (pas encore traduit) (gtk.Frame). N'en tenez cependant pas compte pour l'instant, nous aborderons ce widget plus loin.
Les étiquettes de GTK+ 2.0 peuvent être sélectionnées (pour le copier-coller), et leur texte peut contenir des balises qui modifient la police et d'autres attributs de texte. Ces caractéristiques avancées ne seront toutefois pas abordées ici.
La figure 9.1 montre la fenêtre affichée par le programme etiquettes.py :
Le code source du programme est le suivant :
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.
#
!/usr/bin/env
python
#
exemple
etiquettes.py
import
pygtk
pygtk.require
(
'
2
.
0
'
)
import
gtk
class
Etiquettes:
def
__init__
(
self):
self.fenetre =
gtk.Window
(
gtk.WINDOW_TOPLEVEL)
self.fenetre.connect
(
"
destroy
"
, gtk.main_quit)
self.fenetre.set_title
(
"
Étiquettes
"
)
boite_v =
gtk.VBox
(
False
, 5
)
boite_h =
gtk.HBox
(
False
, 5
)
self.fenetre.add
(
boite_h)
boite_h.pack_start
(
boite_v, False
, False
, 0
)
self.fenetre.set_border_width
(
5
)
cadre =
gtk.Frame
(
"
Etiquette
normale
"
)
etiquette =
gtk.Label
(
"
Voici
une
étiquette
normale
"
)
cadre.add
(
etiquette)
boite_v.pack_start
(
cadre, False
, False
, 0
)
cadre =
gtk.Frame
(
"
Etiquette
de
plusieurs
lignes
"
)
etiquette =
gtk.Label
(
"
Voici
une
étiquette
de
plusieurs
lignes
.
\n
Deuxieme
ligne
\n
"
"
Troisième
ligne
"
)
cadre.add
(
etiquette)
boite_v.pack_start
(
cadre, False
, False
, 0
)
cadre =
gtk.Frame
(
"
Étiquette
alignée
à
gauche
"
)
etiquette =
gtk.Label
(
"
Voici
une
étiquette
de
plusieurs
lignes
\n
"
"
dont
le
texte
est
aligné
à
gauche
.
\n
Troisieme
ligne
"
)
etiquette.set_justify
(
gtk.JUSTIFY_LEFT)
cadre.add
(
etiquette)
boite_v.pack_start
(
cadre, False
, False
, 0
)
cadre =
gtk.Frame
(
"
Étiquette
alignée
à
droite
"
)
etiquette =
gtk.Label
(
"
Voici
une
étiquette
de
plusieurs
lignes
\n
dont
le
texte
est
aligné
à
droite
.
\n
"
"
Quatrième
ligne
,
(
j
/
k
)
"
)
etiquette.set_justify
(
gtk.JUSTIFY_RIGHT)
cadre.add
(
etiquette)
boite_v.pack_start
(
cadre, False
, False
, 0
)
boite_v =
gtk.VBox
(
False
, 5
)
boite_h.pack_start
(
boite_v, False
, False
, 0
)
cadre =
gtk.Frame
(
"
Étiquette
avec
retour
à
la
ligne
auto
"
)
etiquette =
gtk.Label
(
"
Voici
un
exemple
d
'
étiquette
avec
retour
à
la
ligne
auto
.
Elle
"
"
ne
doit
pas
remplir
l
'
espace
qui
lui
est
"
"
alloué
,
mais
elle
s
'
ajuste
automatiquement
"
"
en
renvoyant
les
mots
à
la
ligne
.
"
"
Lorem
ipsum
dolor
sit
amet
,
consectetur
adipisicing
elit
,
sed
"
"
do
eiusmod
tempor
incididunt
ut
labore
et
dolore
magna
aliqua
.
"
"
Seize
jacinthes
sèchent
dans
seize
sachets
secs
.
\n
"
"
Ces
étiquettes
peuvent
contenir
plusieurs
paragraphes
"
"
et
ajoutent
correctement
"
"
de
nombreux
espaces
supplémentaires
"
)
etiquette.set_line_wrap
(
True
)
cadre.add
(
etiquette)
boite_v.pack_start
(
cadre, False
, False
, 0
)
cadre =
gtk.Frame
(
"
Étiquette
justifiee
avec
retour
a
la
ligne
auto
"
)
etiquette =
gtk.Label
(
"
Voici
un
exemple
d
'
étiquette
justifiée
avec
retour
à
la
ligne
auto
.
"
"
Elle
doit
remplir
"
"
entièrement
l
'
espace
qui
lui
est
alloué
.
"
"
Quelques
phrases
pour
les
besoins
de
la
"
"
démonstration
:
Voila
,
voila
.
Le
lundi
au
soleil
,
"
"
c
'
est
une
chose
qu
'
on
n
'
aura
jamais
,
ta
la
la
ta
da
la
la
.
.
.
\n
"
"
Nouveau
paragraphe
.
\n
"
"
Nouveau
paragraphe
,
mais
mieux
que
"
"
l
'
autre
.
Hélas
!
Il
est
déjà
fini
.
"
)
etiquette.set_justify
(
gtk.JUSTIFY_FILL)
etiquette.set_line_wrap
(
True
)
cadre.add
(
etiquette)
boite_v.pack_start
(
cadre, False
, False
, 0
)
cadre =
gtk.Frame
(
"
Etiquette
avec
texte
souligne
"
)
etiquette =
gtk.Label
(
"
Cette
étiquette
comporte
du
texte
souligné
!
\n
"
"
Cette
phrase
est
bizarrement
soulignee
"
)
etiquette.set_justify
(
gtk.JUSTIFY_LEFT)
etiquette.set_pattern
(
"
____________________________________________
_
_________
_
______
__
_______
___
"
)
cadre.add
(
etiquette)
boite_v.pack_start
(
cadre, False
, False
, 0
)
self.fenetre.show_all (
)
def
main
(
):
gtk.main
(
)
return
0
if
__name__
=
=
"
__main__
"
:
Etiquettes
(
)
main
(
)
À noter que le "Étiquette justifiée avec retour à la ligne auto" n'est pas rempli.
9-2. Les flèches▲
Le widget gtk.Arrow consiste en une tête de flèche pouvant pointer dans différentes directions et à laquelle on peut appliquer un certain nombre de styles. Dans beaucoup d'applications, ce widget se révélera très utile une fois placé à l'intérieur d'un bouton. À l'instar des étiquettes, il n'émet pas de signaux.
Pour manipuler les flèches, il n'y a que deux appels :
2.
3.
fleche =
gtk.Arrow
(
arrow_type, shadow_type)
fleche.set(
arrow_type, shadow_type)
Le premier crée une flèche, en prenant en compte le type et le style demandés. Le second appel permet de modifier ces valeurs après la création. L'argument arrow_type (type de flèche) peut prendre l'une des valeurs suivantes :
2.
3.
4.
ARROW_UP #
haut
ARROW_DOWN #
bas
ARROW_LEFT #
gauche#!/usr/bin/env
python
ARROW_RIGHT #
droite
Ces valeurs indiquent évidemment la direction dans laquelle pointera la flèche. Les valeurs possibles pour l'argument shadow_type (type d'ombre) sont :
2.
3.
4.
SHADOW_IN #
empreinte
SHADOW_OUT #
relief
(par
défaut)
SHADOW_ETCHED_IN #
contour
en
empreinte
SHADOW_ETCHED_OUT #
contour
en
relief
Le programme exemple fleches.py donne un aperçu de l'utilisation du widget gtk.Arrow. La Figure 9.2 montre la fenêtre que l'on obtient au lancement du programme :
Voici le code source de fleches.py :
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.
#
!/usr/bin/env
python
#
exemple
fleches.py
import
pygtk
pygtk.require
(
'
2
.
0
'
)
import
gtk
#
On
crée
une
flèche
avec
les
paramètres
spécifiés
#
et
on
la
place
dans
un
bouton
def
cree_fleche_bouton
(
type, ombre):
bouton =
gtk.Button
(
);
fleche =
gtk.Arrow
(
type, ombre);
bouton.add
(
fleche)
bouton.show
(
)
fleche.show
(
)
return
bouton
class
Fleches:
def
__init__
(
self):
#
Création
d'une
fenêtre
fenetre =
gtk.Window
(
gtk.WINDOW_TOPLEVEL)
fenetre.set_title
(
"
Flèches
dans
boutons
"
)
#
C'est
une
bonne
idée
de
faire
ceci
pour
chaque
fenêtre
fenetre.connect
(
"
destroy
"
, gtk.main_quit)
#
On
fixe
la
largeur
des
bordures
de
la
fenêtre
fenetre.set_border_width
(
10
)
#
On
crée
une
boôte
pour
contenir
les
boutons/flèches
boite =
gtk.HBox
(
False
, 0
)
boite.set_border_width
(
2
)
fenetre.add
(
boite)
#
On
place
et
on
affiche
tous
nos
widgets
boite.show
(
)
bouton =
cree_fleche_bouton
(
gtk.ARROW_UP, gtk.SHADOW_IN)
boite.pack_start
(
bouton, False
, False
, 3
)
bouton =
cree_fleche_bouton
(
gtk.ARROW_DOWN, gtk.SHADOW_OUT)
boite.pack_start
(
bouton, False
, False
, 3
)
bouton =
cree_fleche_bouton
(
gtk.ARROW_LEFT, gtk.SHADOW_ETCHED_IN)
boite.pack_start
(
bouton, False
, False
, 3
)
bouton =
cree_fleche_bouton
(
gtk.ARROW_RIGHT, gtk.SHADOW_ETCHED_OUT)
boite.pack_start
(
bouton, False
, False
, 3
)
fenetre.show
(
)
def
main
(
):
gtk.main
(
)
return
0
if
__name__
=
=
"
__main__
"
:
Fleches
(
)
main
(
)
9-3. Les infobulles▲
Les infobulles sont les petites chaînes de texte qui apparaissent lorsque le pointeur de la souris est maintenu quelques secondes au-dessus d'un bouton ou de tout autre widget (à l'exception de ceux qui ne reçoivent pas d'évènements — qui ne disposent pas de leur propre fenêtre).
Dans un premier temps, on utilise l'appel qui suit pour créer une infobulle. Il suffit de le faire une fois pour un groupe d'infobulles donné, car l'objet gtk.Tooltips renvoyé peut être utilisé pour en créer de nouvelles.
infobulles =
gtk.Tooltips
(
)
Une fois créés l'infobulle ainsi que le widget auquel on souhaite la rattacher, on utilisera simplement l'appel suivant pour appliquer la première au second :
infobulles.set_tip
(
widget, tip_text, tip_private=
None
)
L'objet infobulles est l'infobulle que l'on a créée auparavant. Le premier argument (widget) est le widget pour lequel elle doit apparaître et le second (tip_text) le texte qu'elle doit afficher. Le dernier argument (tip_private) est une chaîne de caractères pouvant servir d'identifiant.
Le programme exemple infobulles.py modifie le programme fleches.py en ajoutant une infobulle à chaque bouton. La Figure 9.3 montre la fenêtre qu'il génère ainsi que l'infobulle du deuxième bouton :
Voici le code source de infobulles.py :
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.
#
!/usr/bin/env
python
#
exemple
infobulles.py
import
pygtk
pygtk.require
(
'
2
.
0
'
)
import
gtk
#
On
crée
une
flèche
avec
les
paramètres
spécifiés
#
et
on
la
place
dans
un
bouton
def
cree_fleche_bouton
(
type, ombre):
bouton =
gtk.Button
(
);
fleche =
gtk.Arrow
(
type, ombre);
bouton.add
(
fleche)
bouton.show
(
)
fleche.show
(
)
return
bouton
class
Infobulles:
def
__init__
(
self):
#
Créeation
d'une
fenêtre
fenetre =
gtk.Window
(
gtk.WINDOW_TOPLEVEL)
fenetre.set_title
(
"
Infobulles
"
)
#
C'est
une
bonne
idée
de
faire
ceci
pour
chaque
fenêtre
fenetre.connect
(
"
destroy
"
, gtk.main_quit)
#
On
fixe
la
largeur
des
bordures
de
la
fenetre
fenetre.set_border_width
(
10
)
#
On
crée
une
boîte
pour
contenir
les
boutons/flèches
boite =
gtk.HBox
(
False
, 0
)
boite.set_border_width
(
2
)
fenetre.add
(
boite)
#
Création
d'un
objet
Tooltips
self.infobulles =
gtk.Tooltips
(
)
#
On
place
et
on
affiche
tous
nos
widgets
boite.show
(
)
bouton =
cree_fleche_bouton
(
gtk.ARROW_UP, gtk.SHADOW_IN)
boite.pack_start
(
bouton, False
, False
, 3
)
self.infobulles.set_tip
(
bouton, "
SHADOW_IN
"
)
bouton =
cree_fleche_bouton
(
gtk.ARROW_DOWN, gtk.SHADOW_OUT)
boite.pack_start
(
bouton, False
, False
, 3
)
self.infobulles.set_tip
(
bouton, "
SHADOW_OUT
"
)
bouton =
cree_fleche_bouton
(
gtk.ARROW_LEFT, gtk.SHADOW_ETCHED_IN)
boite.pack_start
(
bouton, False
, False
, 3
)
self.infobulles.set_tip
(
bouton, "
SHADOW_ETCHED_IN
"
)
bouton =
cree_fleche_bouton
(
gtk.ARROW_RIGHT, gtk.SHADOW_ETCHED_OUT)
boite.pack_start
(
bouton, False
, False
, 3
)
self.infobulles.set_tip
(
bouton, "
SHADOW_ETCHED_OUT
"
)
fenetre.show
(
)
def
main
(
):
gtk.main
(
)
return
0
if
__name__
=
=
"
__main__
"
:
infob =
Infobulles
(
)
main
(
)
Il existe d'autres méthodes utilisables avec les infobulles. En voici une liste, accompagnée d'une brève description pour chacune :
infobulles.enable
(
)
Active un groupe d'infobulles désactivé.
infobulles.disable
(
)
Désactive une groupe d'infobulles activé.
infobulles.set_delay
(
delay)
Fixe le nombre de millisecondes pour lequel le pointeur de la souris doit rester au-dessus du widget avant que l'infobulle apparaisse. La valeur par défaut est 500 millisecondes (une demi-seconde).
Et voilà. C'est déjà plus qu'il n'en faut :-).
9-4. La barre de progression▲
On emploie la barre de progression pour montrer l'état d'avancement d'une opération. Son utilisation est très facile, comme vous pourrez le constater plus bas avec le code source de notre exemple. Mais commençons par découvrir son appel de création :
barreprogression =
gtk.ProgressBar
(
adjustment=
None
)
L'argument adjustment indique un ajustement à utiliser avec la barre de progression. Si aucun n'est spécifié, il en sera créé un automatiquement. À présent que notre barre de progression existe, nous pouvons l'utiliser.
barreprogression.set_fraction
(
fraction)
L'objet barreprogression est la barre de progression sur laquelle l'on souhaite agir, et l'argument fraction la proportion "effectuée", c'est-à-dire le pourcentage de remplissage de la barre de progression. Cette indication est donnée à la méthode sous la forme d'un réel compris entre 0 et 1.
L'orientation de la barre de progression peut être définie avec la méthode :
barreprogression.set_orientation
(
orientation)
L'argument orientation peut prendre les valeurs suivantes, qui indiquent le sens de progression de la barre :
2.
3.
4.
PROGRESS_LEFT_TO_RIGHT #
de
gauche
à
droite
PROGRESS_RIGHT_TO_LEFT #
de
droite
à
gauche
PROGRESS_BOTTOM_TO_TOP #
de
bas
en
haut
PROGRESS_TOP_TO_BOTTOM #
de
haut
en
bas
On peut configurer la barre de progression pour que, plutôt que de donner l'état d'avancement de l'opération, elle indique juste un état d'activité. Cela peut servir dans des situations où l'état d'avancement ne peut pas être représenté dans un intervalle de valeurs. La fonction suivante indique que l'opération a avancé dans une certaine mesure.
barreprogression.pulse
(
)
Le pas de déplacement de l'indicateur d'activité se définit avec la méthode suivante, où fraction est compris entre 0.0 et 1.0.
barreprogression.set_pulse_step
(
fraction)
Lorsqu'elle n'est pas en mode "activité", la barre de progression peut également afficher une chaîne de texte configurable dans sa coulisse. On utilise alors la méthode suivante :
barreprogression.set_text
(
text)
Notez que set_text() ne prend pas en charge le formatage de type printf() des barre de progression de GTK+ 1.2.
Pour désactiver l'affichage de la chaîne de caractères, on appelle set_text() à nouveau, mais sans argument.
Le texte présent dans une barre de progression peut se récupérer à l'aide de la méthode suivante :
text =
barreprogression.get_text
(
)
Les barres de progression sont généralement utilisées avec des temporisations ou d'autres fonctions de ce genre (cf. Chapitre 19. Temporisations, Entrées/Sorties et fonctions d'inactivitéChapitre 19. Temporisations, Entrées/Sorties et fonctions d'inactivité) pour donner une illusion de mode multitâche. Dans tous les cas, les fonctions set_fraction() ou pulse() sont employées de la même manière.
Le programme barreprogression.py offre un exemple de barre de progression actualisée par l'intermédiaire de temporisations. Ce code vous montre en outre comment réinitialiser la barre de progression. La Figure 9.4 montre la fenêtre que l'on obtient :
Voici le code source de barreprogression.py :
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.
#
!/usr/bin/env
python
#
exemple
barreprogression.py
import
pygtk
pygtk.require
(
'
2
.
0
'
)
import
gtk
#
Fonction
qui
actualise
la
valeur
de
la
barre
de
progression
#
pour
qu'on
ait
un
petit
peu
de
mouvement
def
tempo_progression
(
objetbarre):
if
objetbarre.case_activite.get_active
(
):
objetbarre.barreprogression.pulse
(
)
else
:
#
On
calcule
la
valeur
de
la
barre
de
progression
en
prenant
#
en
compte
l'intervalle
défini
dans
l'ajustement
nouv_val =
objetbarre.barreprogression.get_fraction
(
) +
0.01
if
nouv_val >
1.0
:
nouv_val =
0.0
#
On
fixe
la
nouvelle
valeur
objetbarre.barreprogression.set_fraction
(
nouv_val)
#
Cette
fonction
étant
une
fonction
de
temporisation,
on
#
renvoie
TRUE
afin
qu'elle
puisse
encore
être
appelée
return
True
class
BarreProgression:
#
Fonction
de
rappel
qui
active
ou
désactive
l'affichage
du
texte
#
dans
la
coulisse
de
la
barre
de
progression
def
modif_affich_texte
(
self, widget, data=
None
):
if
widget.get_active
(
):
self.barreprogression.set_text
(
"
exemple
de
texte
"
)
else
:
self.barreprogression.set_text
(
"
"
)
#
Fonction
de
rappel
qui
active
ou
désactive
le
mode
"activite"
de
#
la
barre
de
progression
def
modif_mode
(
self, widget, data=
None
):
if
widget.get_active
(
):
self.barreprogression.pulse
(
)
else
:
self.barreprogression.set_fraction
(
0.0
)
#
Fonction
de
rappel
qui
modifie
l'orientation
de
la
barre
de
progression
def
modif_orientation
(
self, widget, data=
None
):
if
self.barreprogression.get_orientation
(
) =
=
gtk.PROGRESS_LEFT_TO_RIGHT:
self.barreprogression.set_orientation
(
gtk.PROGRESS_RIGHT_TO_LEFT)
elif
self.barreprogression.get_orientation
(
) =
=
gtk.PROGRESS_RIGHT_TO_LEFT:
self.barreprogression.set_orientation
(
gtk.PROGRESS_LEFT_TO_RIGHT)
#
Liberation
de
la
mémoire
réservée
et
retrait
de
la
temporisation
def
sortie
(
self, widget, data=
None
):
gtk.timeout_remove
(
self.tempo)
self.tempo =
0
gtk.main_quit
(
)
def
__init__
(
self):
self.fenetre =
gtk.Window
(
gtk.WINDOW_TOPLEVEL)
self.fenetre.set_resizable
(
True
)
self.fenetre.connect
(
"
destroy
"
, self.sortie)
self.fenetre.set_title
(
"
Barre
de
progression
"
)
self.fenetre.set_border_width
(
0
)
boite_v =
gtk.VBox
(
False
, 5
)
boite_v.set_border_width
(
10
)
self.fenetre.add
(
boite_v)
boite_v.show
(
)
#
Création
d'un
objet
alignement
au
centre
align =
gtk.Alignment
(
0.5
, 0.5
, 0
, 0
)
boite_v.pack_start
(
align, False
, False
, 5
)
align.show
(
)
#
Création
de
la
barre
de
progression
en
utilisant
l'ajustement
self.barreprogression =
gtk.ProgressBar
(
)
align.add
(
self.barreprogression)
self.barreprogression.show
(
)
#
On
ajoute
une
fonction
de
rappel
temporisée,
qui
actualisera
#
la
valeur
de
la
barre
de
progression
self.tempo =
gtk.timeout_add (
100
, tempo_progression, self)
separateur =
gtk.HSeparator
(
)
boite_v.pack_start
(
separateur, False
, False
, 0
)
separateur.show
(
)
#
lignes,
colonnes,
homogène
tableau =
gtk.Table
(
2
, 2
, False
)
boite_v.pack_start
(
tableau, False
, True
, 0
)
tableau.show
(
)
#
Ajout
d'une
case
à
cocher
pour
l'affichage
du
texte
dans
la
coulisse
case =
gtk.CheckButton
(
"
Afficher
le
texte
"
)
tableau.attach
(
case, 0
, 1
, 0
, 1
,
gtk.EXPAND |
gtk.FILL, gtk.EXPAND |
gtk.FILL,
5
, 5
)
case.connect
(
"
clicked
"
, self.modif_affich_texte)
case.show
(
)
#
Ajout
d'une
case
à
cocher
pour
activer
ou
désactiver
le
mode
"activite"
self.case_activite =
case =
gtk.CheckButton
(
"
Mode
activite
"
)
tableau.attach
(
case, 0
, 1
, 1
, 2
,
gtk.EXPAND |
gtk.FILL, gtk.EXPAND |
gtk.FILL,
5
, 5
)
case.connect
(
"
clicked
"
, self.modif_mode)
case.show
(
)
#
Ajout
d'une
case
à
cocher
pour
modifier
l'orientation
case =
gtk.CheckButton
(
"
De
droite
à
gauche
"
)
tableau.attach
(
case, 0
, 1
, 2
, 3
,
gtk.EXPAND |
gtk.FILL, gtk.EXPAND |
gtk.FILL,
5
, 5
)
case.connect
(
"
clicked
"
, self.modif_orientation)
case.show
(
)
#
Ajout
d'un
bouton
pour
quitter
le
programme
bouton =
gtk.Button
(
"
Fermer
"
)
bouton.connect
(
"
clicked
"
, self.sortie)
boite_v.pack_start
(
bouton, False
, False
, 0
)
#
Ceci
fait
en
sorte
que
le
bouton
puisse
être
le
widget
par
défaut
bouton.set_flags
(
gtk.CAN_DEFAULT)
#
Ceci
fait
du
bouton
le
bouton
par
défaut.
Le
simple
fait
d'appuyer
#
sur
la
touche
"Enter"
l'activera
bouton.grab_default (
)
bouton.show
(
)
self.fenetre.show
(
)
def
main
(
):
gtk.main
(
)
return
0
if
__name__
=
=
"
__main__
"
:
BarreProgression
(
)
main
(
)
9-5. Les boîtes de dialogue▲
Les boîtes de dialogue sont très simples, et ne sont en définitive que des fenêtres dans lesquelles quelques widgets sont pré-placés. Un gtk.Dialog crée une fenêtre, place dans sa partie supérieure une boîte horizontale contenant un séparateur, et place à sa suite une boîte horizontale qui sera la "zone d'action" (action area).
Les boîtes de dialogues peuvent servir pour des messages à destination de l'utilisateur, et pour d'autres tâches similaires. Il s'agit vraiment d'un widget basique, qui ne possède en lui-même qu'une fonction :
boitedialogue =
gtk.Dialog
(
title=
None
, parent=
None
, flags=
0
, buttons=
None
)
L'argument title (titre) attend le texte à utiliser dans la barre de titre, parent représente la fenêtre principale de l'application, et flags (drapeaux) définit plusieurs modes d'opération pour la boîte de dialogue :
2.
3.
DIALOG_MODAL #
rend
la
boîte
de
dialogue
modale
DIALOG_DESTROY_WITH_PARENT #
détruit
la
boîte
de
dialogue
quand
son
parent
est
détruit
DIALOG_NO_SEPARATOR #
pas
de
séparateur
entre
la
boîte
verticale
et
la
zone
d'action
L'argument buttons (boutons) est un tuple contenant pour chaque bouton une couple texte-réponse. Tous les arguments ont des valeurs par défaut et peuvent être spécifiés avec des mots-clés.
Vous savez maintenant créer une boîte de dialogue. Il ne vous reste plus qu'à vous en servir. Vous pourriez placer un bouton dans la zone d'action :
2.
3.
bouton =
...
boitedialogue.action_area.pack_start
(
bouton, True
, True
, 0
)
bouton.show
(
)
Vous pourriez également enrichir votre boîte verticale d'une étiquette, par exemple. Essayer quelque chose dans ce style :
2.
3.
etiquette =
gtk.Label
(
"
Cool
,
la
boîte
de
dialogue
"
)
boitedialogue.vbox.pack_start
(
etiquette, True
, True
, 0
)
etiquette.show
(
)
En guise d'exemple d'utilisation de la boîte de dialogue, vous pourriez mettre deux boutons dans la zone d'action, un bouton Annuler et un bouton OK, puis placer une étiquette dans la boîte verticale qui interrogerait l'utilisateur ou l'informerait d'une erreur. Vous connecteriez ensuite un signal différent à chacun des boutons et feriez en sorte que l'opération choisie soit exécutée.
Si la simple configuration par défaut (boîtes verticale et horizontale dans les deux zones de la fenêtre) ne vous offre pas assez de possibilités pour ce que vous souhaitez faire dans votre application, rien ne vous empêche de placer un autre widget de placement dans les boîtes. Il est tout à fait possible, par exemple, de placer un tableau dans la boîte verticale.
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 :
2.
3.
4.
5.
6.
7.
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 :
2.
3.
4.
5.
6.
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 #
"
:
boîte
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 :
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.
87.
88.
89.
90.
91.
92.
#
!/usr/bin/env
python
#
exemple
images.py
import
pygtk
pygtk.require
(
'
2
.
0
'
)
import
gtk
class
ImagesExemple:
#
Si
elle
est
invoquée
(via
le
"delete_event"),
cette
fonction
ferme
l'application
def
fermer_application
(
self, widget, evnmt, data=
None
):
gtk.main_quit
(
)
return
False
#
Cette
fonction
est
invoquée
quand
on
clique
sur
le
bouton.
Elle
affiche
un
message.
def
clic_bouton
(
self, widget, data=
None
):
print
"
Clic
sur
le
bouton
%s
"
%
data
def
__init__
(
self):
#
création
de
la
fenêtre
principale,
et
connexion
du
signal
#
delete_event
à
la
fermeture
de
l'application
fenetre =
gtk.Window
(
gtk.WINDOW_TOPLEVEL)
fenetre.connect
(
"
delete_event
"
, self.fermer_application)
fenetre.set_border_width
(
10
)
fenetre.show
(
)
#
Une
boîte
horizontale
pour
contenir
les
boutons
boite_h =
gtk.HBox
(
)
boite_h.show
(
)
fenetre.add
(
boite_h)
animpixbuf =
gtk.gdk.PixbufAnimation
(
"
goal
.
gif
"
)
image =
gtk.Image
(
)
image.set_from_animation
(
animpixbuf)
image.show
(
)
#
un
bouton
pour
contenir
le
widget
image
bouton =
gtk.Button
(
)
bouton.add
(
image)
bouton.show
(
)
boite_h.pack_start
(
bouton)
bouton.connect
(
"
clicked
"
, self.clic_bouton, "
1
"
)
#
création
de
plusieurs
gtk.Image
à
partir
de
données
de
#
fichiers,
et
chargement
dans
des
boutons
image =
gtk.Image
(
)
image.set_from_file
(
"
pomme
-
rouge
.
png
"
)
image.show
(
)
#
un
bouton
pour
contenir
le
widget
image
bouton =
gtk.Button
(
)
bouton.add
(
image)
bouton.show
(
)
boite_h.pack_start
(
bouton)
bouton.connect
(
"
clicked
"
, self.clic_bouton, "
2
"
)
image =
gtk.Image
(
)
image.set_from_file
(
"
chaos
.
jpg
"
)
image.show
(
)
#
un
bouton
pour
contenir
le
widget
image
bouton =
gtk.Button
(
)
bouton.add
(
image)
bouton.show
(
)
boite_h.pack_start
(
bouton)
bouton.connect
(
"
clicked
"
, self.clic_bouton, "
3
"
)
image =
gtk.Image
(
)
image.set_from_file
(
"
important
.
tif
"
)
image.show
(
)
#
un
bouton
pour
contenir
le
widget
image
bouton =
gtk.Button
(
)
bouton.add
(
image)
bouton.show
(
)
boite_h.pack_start
(
bouton)
bouton.connect
(
"
clicked
"
, self.clic_bouton, "
4
"
)
image =
gtk.Image
(
)
image.set_from_file
(
"
ballonfoot
.
gif
"
)
image.show
(
)
#
un
bouton
pour
contenir
le
widget
image
bouton =
gtk.Button
(
)
bouton.add
(
image)
bouton.show
(
)
boite_h.pack_start
(
bouton)
bouton.connect
(
"
clicked
"
, self.clic_bouton, "
5
"
)
def
main
(
):
gtk.main
(
)
return
0
if
__name__
=
=
"
__main__
"
:
ImagesExemple
(
)
main
(
)
9-6-1. Les pixmaps▲
Les pixmaps sont des structures de données qui contiennent des imagesqui 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 deux couleurs est un bitmap. Des routines additionnelles existent pour manipuler ce cas, relativement commun, à part.
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 spé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 :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
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 :
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.
#
!/usr/bin/env
python
#
exemple
pixmap.py
import
pygtk
pygtk.require
(
'
2
.
0
'
)
import
gtk
#
Données
XPM
d'une
icône
"Ouvrir
Fichier"
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
.
"
,
"
.
.
.
.
.
.
.
.
.
"
,
"
"
,
"
"
]
class
ExemplePixmap:
#
Si
elle
est
invoquée
(via
le
"delete_event"),
cette
fonction
ferme
l'application
def
fermer_application
(
self, widget, evnmt, data=
None
):
gtk.main_quit
(
)
return
False
#
Fonction
invoquée
par
un
clic
sur
le
bouton.
Elle
affiche
juste
un
message.
def
clic_bouton
(
self, widget, data=
None
):
print
"
Clic
sur
le
bouton
"
def
__init__
(
self):
#
création
de
la
fenêtre
principale,
et
connexion
du
signal
#
delete_event
a
la
fermeture
de
l'application
fenetre =
gtk.Window
(
gtk.WINDOW_TOPLEVEL)
fenetre.connect
(
"
delete_event
"
, self.fermer_application)
fenetre.set_border_width
(
10
)
fenetre.show
(
)
#
venons-en
à
la
creation
du
pixmap
à
partir
des
données
XPM
pixmap, masque =
gtk.gdk.pixmap_create_from_xpm_d
(
fenetre.window,
None
,
donnees_xpm)
#
Création
d'un
widget
gtk.Image
pour
contenir
le
pixmap
image =
gtk.Image
(
)
image.set_from_pixmap
(
pixmap, masque)
image.show
(
)
#
Création
d'un
bouton
pour
contenir
le
gtk.Image
bouton =
gtk.Button
(
)
bouton.add
(
image)
fenetre.add
(
bouton)
bouton.show
(
)
bouton.connect
(
"
clicked
"
, self.clic_bouton)
def
main
(
):
gtk.main
(
)
return
0
if
__name__
=
=
"
__main__
"
:
ExemplePixmap
(
)
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 :
Voici le code source de brouette.py :
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.
#
!/usr/bin/env
python
#
exemple
brouette.py
import
pygtk
pygtk.require
(
'
2
.
0
'
)
import
gtk
#
XPM
BrouettePleine_xpm =
[
"
48
48
64
1
"
,
"
c
None
"
,
"
.
c
#
DF7DCF3CC71B
"
,
"
X
c
#
965875D669A6
"
,
"
o
c
#
71C671C671C6
"
,
"
O
c
#
A699A289A699
"
,
"
+
c
#
965892489658
"
,
"
@
c
#
8E38410330C2
"
,
"
#
c
#
D75C7DF769A6
"
,
"
$
c
#
F7DECF3CC71B
"
,
"
%
c
#
96588A288E38
"
,
"
&
c
#
A69992489E79
"
,
"
*
c
#
8E3886178E38
"
,
"
=
c
#
104008200820
"
,
"
-
c
#
596510401040
"
,
"
;
c
#
C71B30C230C2
"
,
"
:
c
#
C71B9A699658
"
,
"
>
c
#
618561856185
"
,
"
,
c
#
20811C712081
"
,
"
<
c
#
104000000000
"
,
"
1
c
#
861720812081
"
,
"
2
c
#
DF7D4D344103
"
,
"
3
c
#
79E769A671C6
"
,
"
4
c
#
861782078617
"
,
"
5
c
#
41033CF34103
"
,
"
6
c
#
000000000000
"
,
"
7
c
#
49241C711040
"
,
"
8
c
#
492445144924
"
,
"
9
c
#
082008200820
"
,
"
0
c
#
69A618611861
"
,
"
q
c
#
B6DA71C65144
"
,
"
w
c
#
410330C238E3
"
,
"
e
c
#
CF3CBAEAB6DA
"
,
"
r
c
#
71C6451430C2
"
,
"
t
c
#
EFBEDB6CD75C
"
,
"
y
c
#
28A208200820
"
,
"
u
c
#
186110401040
"
,
"
i
c
#
596528A21861
"
,
"
p
c
#
71C661855965
"
,
"
a
c
#
A69996589658
"
,
"
s
c
#
30C228A230C2
"
,
"
d
c
#
BEFBA289AEBA
"
,
"
f
c
#
596545145144
"
,
"
g
c
#
30C230C230C2
"
,
"
h
c
#
8E3882078617
"
,
"
j
c
#
208118612081
"
,
"
k
c
#
38E30C300820
"
,
"
l
c
#
30C2208128A2
"
,
"
z
c
#
38E328A238E3
"
,
"
x
c
#
514438E34924
"
,
"
c
c
#
618555555965
"
,
"
v
c
#
30C2208130C2
"
,
"
b
c
#
38E328A230C2
"
,
"
n
c
#
28A228A228A2
"
,
"
m
c
#
41032CB228A2
"
,
"
M
c
#
104010401040
"
,
"
N
c
#
492438E34103
"
,
"
B
c
#
28A2208128A2
"
,
"
V
c
#
A699596538E3
"
,
"
C
c
#
30C21C711040
"
,
"
Z
c
#
30C218611040
"
,
"
A
c
#
965865955965
"
,
"
S
c
#
618534D32081
"
,
"
D
c
#
38E31C711040
"
,
"
F
c
#
082000000820
"
,
"
"
,
"
.
XoO
"
,
"
+
@
#
$
%o
&
"
,
"
*
=
-
;
#
:
:
o
+
"
,
"
>
,
<
12
#
:
34
"
,
"
45671
#
:
X3
"
,
"
+
89
<
02qwo
"
,
"
e
*
>
,
67
;
ro
"
,
"
ty
>
459
@
>
+
&
&
"
,
"
$
2u
+
>
"
,
"
Oh
$
;
ya
*
3d
.
a8j
,
Xe
.
d3g8
+
"
,
"
Oh
$
;
ka
*
3d
$
a8lz
,
,
xxc
:
.
e3g54
"
,
"
Oh
$
;
kO
*
pd
$
%s
vbzz
,
sxxxxfX
.
.
&
wn
>
"
,
"
Oh
$
@
mO
*
3dthwlsslszjzxxxxxxx3
:
td8M4
"
,
"
Oh
$
@
g
&
*
3d
$
XNlvvvlllm
,
mNwxxxxxxxfa
.
:
,
B
*
"
,
"
Oh
$
@
,
Od
.
czlllllzlmmqV
@
V
#
V
@
fxxxxxxxf
:
%
j5
&
"
,
"
Oh
$
1hd5lllslllCCZrV
#
r
#
:
#
2AxxxxxxxxxcdwM
*
"
,
"
OXq6c
.
%
8vvvllZZiqqApA
:
mq
:
Xxcpcxxxxxfdc9
*
"
,
"
2r
<
6gde3bllZZrVi7S
@
SV77A
:
:
qApxxxxxxfdcM
"
,
"
:
,
q
-
6MN
.
dfmZZrrSS
:
#
riirDSAX
@
Af5xxxxxfevo
"
,
"
+
A26jguXtAZZZC7iDiCCrVVii7Cmmmxxxxxx
%3g
"
,
"
*
#
16jszN
.
.
3DZZZZrCVSA2rZrV7Dmmwxxxx
&
en
"
,
"
p2yFvzssXe
:
fCZZCiiD7iiZDiDSSZwwxx8e
*
>
"
,
"
OA1666
>
=
01
-
kuu666
>
"
,
"
,
6ky
&
&
46
-
10ul
,
66
,
"
,
"
Ou0
<
>
o66y66By7
=
xu664
"
,
"
<
>
+
66uv
,
zN666
*
"
,
"
566
,
xxj669
"
,
"
4666FF666
>
"
,
"
>
966666M
"
,
"
oM6668
+
"
,
"
*
4
"
,
"
"
,
"
"
]
class
ExempleBrouette:
#
Si
elle
est
invoquée
(via
le
"delete_event"),
cette
fonction
ferme
l'application
def
fermer_application
(
self, widget, evnmt, data=
None
):
gtk.main_quit
(
)
return
False
def
__init__
(
self):
#
Création
de
la
fenêtre
principale
et
connexion
du
signal
"delete_event"
#
à
la
fermeture
de
l'application.
Notez
que
la
fenêtre
principale
n'aura
#
pas
de
barre
de
titre,
car
nous
la
définissons
comme
popup.
fenetre =
gtk.Window
(
gtk.WINDOW_POPUP)
fenetre.connect
(
"
delete_event
"
, self.fermer_application)
fenetre.set_events
(
fenetre.get_events
(
) |
gtk.gdk.BUTTON_PRESS_MASK)
fenetre.connect
(
"
button_press_event
"
, self.fermer_application)
fenetre.show
(
)
#
Venons-en
a
la
création
du
pixmap
et
du
widget
gtk.Image
pixmap, masque =
gtk.gdk.pixmap_create_from_xpm_d
(
fenetre.window, None
, BrouettePleine_xpm)
image =
gtk.Image
(
)
image.set_from_pixmap
(
pixmap, masque)
image.show
(
)
#
Pour
afficher
l'image,
on
va
la
placer
dans
un
widget
fixe
wfixe =
gtk.Fixed
(
)
wfixe.set_size_request
(
200
, 200
)
wfixe.put
(
image, 0
, 0
)
fenetre.add
(
wfixe)
wfixe.show
(
)
#
Ici
nous
masquons
tout
sauf
l'image
elle-même
fenetre.shape_combine_mask
(
masque, 0
, 0
)
#
On
affiche
la
fenêtre
fenetre.set_position
(
gtk.WIN_POS_CENTER_ALWAYS)
fenetre.show
(
)
def
main
(
):
gtk.main
(
)
return
0
if
__name__
=
=
"
__main__
"
:
ExempleBrouette
(
)
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.
9-7. Les règles▲
Le widget gtk.Ruler sert à indiquer la position du pointeur de la souris dans une fenêtre donnée. Une fenêtre peut être dotée d'une règle horizontale s'étendant sur sa largeur et d'une verticale dans sa hauteur. La position exacte du pointeur mesurée par la règle est matérialisée sur celle-ci par un petit indicateur triangulaire.
Le widget doit tout d'abord être créé. On utilisera à cet effet les fonctions suivantes :
2.
3.
regle_h =
gtk.HRuler
(
) #
crée
une
règle
horizontale
regle_v =
gtk.VRuler
(
) #
crée
une
règle
verticale
Une fois qu'une règle est créée, on peut définir l'unité de mesure : PIXELS (pixels), INCHES (pouces) ou CENTIMETERS (centimètres). La méthode à utiliser est la suivante :
regle.set_metric
(
metric)
L'unité de mesure par défaut est PIXELS.
regle.set_metric
(
gtk.PIXELS)
Les gtk.Ruler possèdent d'autres caractéristiques configurables, telles que la graduation de l'intervalle choisi et la position initiale de l'indicateur. Ces deux options se définissent avec la méthode suivante :
regle.set_range
(
lower, upper, position, max_size)
Les arguments lower (minimum) et upper (maximum) spécifient l'étendue de la règle, et max_size (taille maximum) représente le plus grand nombre qui puisse être affiché. Quant à position, il précise la position initiale de l'indicateur triangulaire dans la règle.
On peut donc faire s'étendre une règle verticale sur une fenêtre de 800 pixels de haut ainsi :
regle_v.set_range
(
0
, 800
, 0
, 800
)
Les graduations de la règle iront de 0 à 800, avec un nombre tous les 100 pixels. Si l'on voulait que la règle aille de 7 à 16, on coderait plutôt :
regle_v.set_range
(
7
, 16
, 0
, 20
)
L'indicateur, petite marque triangulaire présente sur la règle, précise la position du pointeur mesurée par cette dernière. Si l'on utilise une règle dans le but de suivre le pointeur de la souris, le signal "motion_notify_event" (évènement "notification de mouvement") devrait être connecté à la méthode "motion_notify_event" de la règle. Il nous faut définir une fonction de rappel du "motion_notify_event" pour la zone de dessin et utiliser connect_object() pour faire émettre à la règle un signal de notification de mouvement :
2.
3.
4.
def
notif_mouvement
(
regle, evnmt):
return
regle.emit
(
"
motion_notify_event
"
, evnmt)
zonedess.connect_object
(
"
motion_notify_event
"
, notif_mouvement, regle)
Le programme d'exemple regles.py crée une zone de dessin encadrée par une règle horizontale en haut et une verticale à gauche. La zone de dessin fait 600 pixels de large pour 800 pixels de haut. La règle horizontale est graduée de 7 à 13 avec une marque tous les 100 pixels, tandis que la règle verticale est graduée de 0 à 400 avec une marque tous les 100 pixels. Le placement de la zone de dessin ainsi que des règles est effectué au moyen d'un tableau. La Figure 9.8 montre le résultat :
Le code source de regles.py est le suivant :
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.
#
!/usr/bin/env
python
#
exemple
regles.py
import
pygtk
pygtk.require
(
'
2
.
0
'
)
import
gtk
class
ExempleRegles:
TAILLE_X =
400
TAILLE_Y =
400
#
Cette
routine
prend
le
controle
lorsque
l'on
clique
sur
le
bouton
fermer
def
fermer_application
(
self, widget, evnmt, data=
None
):
gtk.main_quit
(
)
return
False
def
__init__
(
self):
fenetre =
gtk.Window
(
gtk.WINDOW_TOPLEVEL)
fenetre.connect
(
"
delete_event
"
, self.fermer_application)
fenetre.set_border_width
(
10
)
#
Creation
d'un
tableau
pour
le
placement
des
regles
et
de
la
zone
de
dessin
tableau =
gtk.Table
(
3
, 2
, False
)
fenetre.add
(
tableau)
zonedess =
gtk.DrawingArea
(
)
zonedess.set_size_request
(
self.TAILLE_X, self.TAILLE_Y)
tableau.attach
(
zonedess, 1
, 2
, 1
, 2
,
gtk.EXPAND|
gtk.FILL, gtk.FILL, 0
, 0
)
zonedess.set_events
(
gtk.gdk.POINTER_MOTION_MASK |
gtk.gdk.POINTER_MOTION_HINT_MASK )
#
La
règle
horizontale
va
en
haut.
Quand
la
souris
passe
dans
la
zone
de
dessin,
#
un
"motion_notify-event"
est
transmis
au
gestionnaire
d'évènement
approprié,
#
qui
le
passe
a
son
tour
a
la
règle.
regle_h =
gtk.HRuler
(
)
regle_h.set_metric
(
gtk.PIXELS)
regle_h.set_range
(
7
, 13
, 0
, 20
)
def
notif_mouvmt
(
regle, evnmt):
return
regle.emit
(
"
motion_notify_event
"
, evnmt)
zonedess.connect_object
(
"
motion_notify_event
"
, notif_mouvmt, regle_h)
tableau.attach
(
regle_h, 1
, 2
, 0
, 1
,
gtk.EXPAND|
gtk.SHRINK|
gtk.FILL, gtk.FILL, 0
, 0
)
#
La
régle
verticale
va
à
gauche.
Quand
la
souris
passe
dans
la
zone
de
dessin,
#
un
"motion_notify-event"
est
transmis
au
gestionnaire
d'évènement
approprié,
#
qui
le
passe
a
son
tour
a
la
règle.
regle_v =
gtk.VRuler
(
)
regle_v.set_metric
(
gtk.PIXELS)
regle_v.set_range
(
0
, self.TAILLE_Y, 10
, self.TAILLE_Y)
zonedess.connect_object
(
"
motion_notify_event
"
, notif_mouvmt, regle_v)
tableau.attach
(
regle_v, 0
, 1
, 1
, 2
,
gtk.FILL, gtk.EXPAND|
gtk.SHRINK|
gtk.FILL, 0
, 0
)
#
On
affiche
tout
zonedess.show
(
)
regle_h.show
(
)
regle_v.show
(
)
tableau.show
(
)
fenetre.show
(
)
def
main
(
):
gtk.main
(
)
return
0
if
__name__
=
=
"
__main__
"
:
ExempleRegles
(
)
main
(
)
Les lignes 42 et 52 connectent la fonction de rappel notif_mouvmt() à la zone de dessin, la première ligne passant regle_h et la seconde regle_v comme données utilisateur. La fonction de rappel notif_mouvmt() sera invoquée deux fois à chaque mouvement de la souris : une fois avec regle_h et une autre avec regle_v.
9-8. La barre d'état▲
La barre d'état (gtk.Statusbar) est un widget assez simple qui sert à afficher un message textuel. Elle tient à jour une pile des messages qu'on lui a donnés, de sorte que le fait de dépiler le message courant entraine le ré-affichage du précédent.
Afin de permettre l'utilisation de la même barre d'état par différentes parties d'une application, le widget gtk.Statusbar distribue des "identifiants contextuels" qui serviront à identifier différents "utilisateurs". Le message affiché est celui qui se trouve au sommet de la pile, peu importe son contexte. Les messages sont empilés suivant le schéma "dernier entré/premier sorti", et non suivant leur identifiant contextuel.
On crée une barre d'état avec un appel à :
barredetat =
gtk.Statusbar
(
)
On obtient un nouvel identifiant contextuel en invoquant la méthode suivante avec une courte description textuelle du contexte (context_description) :
context_id =
barredetat.get_context_id
(
context_description)
Trois autres méthodes agissent sur les barres d'état :
2.
3.
4.
5.
message_id =
barredetat.push
(
context_id, text)
barredetat.pop
(
context_id)
barredetat.remove
(
context_id, message_id)
La première, push() (empiler), sert à ajouter un nouveau message à barredetat. Elle renvoie un identifiant de message (message_id). Ce dernier, accompagné du context_id approprié peut être transmis plus tard à la méthode remove() (retirer) afin de retirer le message de la pile de barredetat.
La méthode pop() retire le message, ayant le context_id spécifié, qui se trouve le plus haut placé dans la pile.
Le programme d'exemple barredetat.py crée une barre d'état ainsi que deux boutons : un pour empiler des éléments dans la barre d'état, et un autre pour dépiler le dernier élément affiché. La Figure 9.9 montre le résultat :
Voici le code source de barredetat.py :
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.
#
!/usr/bin/env
python
#
exemple
barredetat.py
import
pygtk
pygtk.require
(
'
2
.
0
'
)
import
gtk
class
ExempleBarreEtat:
def
empiler
(
self, widget, donnees):
tampon =
"
Element
%d
"
%
self.compteur
self.compteur =
self.compteur +
1
self.barredetat.push
(
donnees, tampon)
return
def
depiler
(
self, widget, donnees):
self.barredetat.pop
(
donnees)
return
def
__init__
(
self):
self.compteur =
1
#
Création
d'une
fenêtre
fenetre =
gtk.Window
(
gtk.WINDOW_TOPLEVEL)
fenetre.set_size_request
(
200
, 100
)
fenetre.set_title
(
"
Exemple
de
barre
d
'
état
PyGTK
"
)
fenetre.connect
(
"
delete_event
"
, gtk.main_quit)
boite_v =
gtk.VBox
(
False
, 1
)
fenetre.add
(
boite_v)
boite_v.show
(
)
self.barredetat =
gtk.Statusbar
(
)
boite_v.pack_start
(
self.barredetat, True
, True
, 0
)
self.barredetat.show
(
)
context_id =
self.barredetat.get_context_id
(
"
Exemple
barredetat
"
)
bouton =
gtk.Button
(
"
empiler
un
élément
"
)
bouton.connect
(
"
clicked
"
, self.empiler, context_id)
boite_v.pack_start
(
bouton, True
, True
, 2
)
bouton.show
(
)
bouton =
gtk.Button
(
"
dépiler
le
dernier
element
"
)
bouton.connect
(
"
clicked
"
, self.depiler, context_id)
boite_v.pack_start
(
bouton, True
, True
, 2
)
bouton.show
(
)
#
On
affichera
toujours
la
fenêtre
à
la
derniere
etape,
de
sorte
que
#
tout
apparaisse
a
l'ecran
en
un
bloc.
fenetre.show
(
)
def
main
(
):
gtk.main
(
)
return
0
if
__name__
=
=
"
__main__
"
:
ExempleBarreEtat
(
)
main
(
)
9-9. Les champs de saisie▲
Le widget gtk.Entry permet la saisie et l'affichage de texte dans une boîte, sur une seule ligne. Le texte peut être défini en appelant différentes méthodes, lesquelles peuvent soit remplacer intégralement le contenu courant de la boîte, soit y ajouter du texte avant ou après.
La fonction de création d'un champ de saisie est la suivante :
champsaisie =
gtk.Entry
(
max=
0
)
Si l'argument max est spécifié, il fixe une limite de longueur au texte du champ de saisie. S'il vaut 0, aucune limite n'est fixée.
La longueur maximale du champ de saisie peut être modifiée avec la méthode :
champsaisie.set_max_length
(
max)
La méthode qui suit modifie le texte présent dans le gtk.Entry.
champsaisie.set_text
(
text)
La méthode set_text() remplace le contenu courant du champ de saisie par text. Notez que la classe gtk.Entry implémente l'interface Editable (oui, gobject supporte les interfaces "à la Java") qui contient davantage de fonctions pour manipuler le contenu du champ de saisie. Par exemple, la méthode :
champsaisie.insert_text
(
text, position=
0
)
insère text dans champsaisie, à la position spécifiée.
On peut récupérer le contenu du gtk.Entry en appelant la méthode suivante. Cela nous servira pour notre fonction de rappel, plus bas.
texte =
champsaisie.get_text
(
)
Si l'on ne souhaite pas que le contenu du gtk.Entry puisse être modifié en tapant directement du texte dedans, on peut changer son éditabilité.
champsaisie.set_editable
(
is_editable)
La méthode ci-dessus permet de basculer le mode d'éditabilité du champ de saisie en donnant à l'argument is_editable (littéralement : "est éditable") la valeur TRUE (vrai) ou FALSE (faux).
Si l'on utilise le gtk.Entry dans un contexte où le texte saisi ne doit pas être visible, par exemple pour un mot de passe, on peut faire appel à la méthode suivante (qui attend également un drapeau booléen) :
champsaisie.set_visibility
(
visible)
La méthode qui suit permet de définir une partie du texte comme sélectionnée, de start (début) à end (fin). Cette option est principalement utilisée dans les cas où l'on fixe un texte par défaut pour le champ de saisie et que l'on souhaite que l'utilisateur puisse le supprimer facilement.
champsaisie.select_region
(
start, end)
Si l'on veut être prévenu lorsque l'utilisateur a saisi du texte, on peut se connecter aux signaux "activate" ou "changed". activate (activé) est émis lorsque l'utilisateur appuie sur la touche Entrée dans le widget gtk.Entry, et changed (changé) lorsque un changement est apporté au texte (par exemple, pour chaque caractère ajouté ou supprimé).
Le programme d'exemple champsaisie.py illustre l'utilisation d'un widget gtk.Entry. La Figure 9.10 montre ce que l'on obtient en exécutant le programme :
Voici le code source de champsaisie.py :
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.
#
!/usr/bin/env
python
#
exemple
champsaisie.py
import
pygtk
pygtk.require
(
'
2
.
0
'
)
import
gtk
class
ExempleSaisieTexte:
def
fct_rappel_entree
(
self, widget, champsaisie):
textesaisi =
champsaisie.get_text
(
)
print
"
Contenu
de
la
champ
de
saisie
:
%s
\n
"
%
textesaisi
def
champsaisie_editable
(
self, casecocher, champsaisie):
champsaisie.set_editable
(
casecocher.get_active
(
))
def
champsaisie_visible
(
self, casecocher, champsaisie):
champsaisie.set_visibility
(
casecocher.get_active
(
))
def
__init__
(
self):
#
Création
d'une
nouvelle
fenêtre
fenetre =
gtk.Window
(
gtk.WINDOW_TOPLEVEL)
fenetre.set_size_request
(
200
, 100
)
fenetre.set_title
(
"
Saisie
de
texte
GTK
"
)
fenetre.connect
(
"
delete_event
"
, gtk.main_quit)
boite_v =
gtk.VBox
(
False
, 0
)
fenetre.add
(
boite_v)
boite_v.show
(
)
champsaisie =
gtk.Entry
(
)
champsaisie.set_max_length
(
50
)
champsaisie.connect
(
"
activate
"
, self.fct_rappel_entree, champsaisie)
champsaisie.set_text
(
"
salut
"
)
champsaisie.insert_text
(
"
tout
le
monde
"
, len(
champsaisie.get_text
(
)))
champsaisie.select_region
(
0
, len(
champsaisie.get_text
(
)))
boite_v.pack_start
(
champsaisie, True
, True
, 0
)
champsaisie.show
(
)
boite_h =
gtk.HBox
(
False
, 0
)
boite_v.add
(
boite_h)
boite_h.show
(
)
casecocher =
gtk.CheckButton
(
"
Editable
"
)
boite_h.pack_start
(
casecocher, True
, True
, 0
)
casecocher.connect
(
"
toggled
"
, self.champsaisie_editable, champsaisie)
casecocher.set_active
(
True
)
casecocher.show
(
)
casecocher =
gtk.CheckButton
(
"
Visible
"
)
boite_h.pack_start
(
casecocher, True
, True
, 0
)
casecocher.connect
(
"
toggled
"
, self.champsaisie_visible, champsaisie)
casecocher.set_active
(
True
)
casecocher.show
(
)
bouton =
gtk.Button
(
stock=
gtk.STOCK_CLOSE)
bouton.connect_object
(
"
clicked
"
, gtk.main_quit, fenetre)
boite_v.pack_start
(
bouton, True
, True
, 0
)
bouton.set_flags
(
gtk.CAN_DEFAULT)
bouton.grab_default
(
)
bouton.show
(
)
fenetre.show
(
)
def
main
(
):
gtk.main
(
)
return
0
if
__name__
=
=
"
__main__
"
:
ExempleSaisieTexte
(
)
main
(
)
9-10. Les boîtes d'incrément▲
On utilise généralement les boîtes d'incrément (gtk.SpinButton) pour permettre à l'utilisateur de sélectionner une valeur numérique dans un intervalle donné. Ce widget consiste en un champ de texte flanqué de deux boutons fléchés haut et bas. En sélectionnant l'un ou l'autre de ces boutons, on incrémente ou décrémente la valeur dans les limites de l'intervalle. Le champ de texte peut également être édité directement afin de saisir une valeur spécifique.
La valeur d'un gtk.SpinButton peut être affichée sous sa forme entière ou décimale, et il est possible de définir son pas d'incrémentation/décrémentation. On peut également décider que plus l'on maintient enfoncé les boutons, plus cette incrémentation/décrémentation s'accélère.
Les boîtes d'incrément utilisent des ajustementsChapitre 7. Les ajustements pour stocker les données concernant l'intervalle de valeurs du gtk.SpinButton. Cela fait du gtk.SpinButton un widget très puissant.
Pour bien montrer les informations stockées par l'ajustementChapitre 7. Les ajustements, rappelons-nous sa fonction de création :
ajustement =
gtk.Adjustment
(
value=
0
, lower=
0
, upper=
0
, step_incr=
0
, page_incr=
0
, page_size=
0
)
La boîte d'incrément utilise ces attributs de l'ajustement de la manière suivante :
value |
valeur initiale de la boîte d'incrément |
lower |
limite basse de l'intervalle |
upper |
limite haute de l'intervalle |
step_increment |
pas de l'incrémentation/décrémentation lorsque on clique sur l'un des deux boutons avec le bouton 1 de la souris |
page_increment |
pas de l'incrémentation/décrémentation lorsque on clique sur l'un des deux boutons avec le bouton 2 de la souris |
page_size |
inutilisé |
Un clic sur un des deux boutons avec le bouton 3 de la souris peut également servir à aller directement à la valeur upper ou lower. Voyons donc comment créer une boîte à incrément :
boite_increment =
gtk.SpinButton
(
adjustment=
None
, climb_rate=
0.0
, digits=
0
)
L'argument climb_rate accepte une valeur comprise entre 0.0 et 1.0 et indique le degré d'accélération de la boîte d'incrément. L'argument digits spécifie le nombre de décimales de la valeur affichée.
On peut reconfigurer une boîte à incrément après sa création en appelant la méthode suivante :
boite_increment.configure
(
adjustment, climb_rate, digits)
L'argument boite_increment spécifie le gtk.SpinButton à reconfigurer. Les autres arguments sont les mêmes que ceux décrits plus haut.
L'ajustement (adjustment) peut être défini et récupéré indépendamment à l'aide des deux méthodes suivantes :
2.
3.
boite_increment.set_adjustment
(
adjustment)
ajustement =
spin_button.get_adjustment
(
)
On peut également modifier le nombre de décimales ainsi :
boite_increment.set_digits
(
digits)
La valeur affichée par une boîte d'incrément peut être changée avec cette méthode :
boite_increment.set_value
(
value)
La valeur courante d'une boîte d'incrément peut être récupérée sous sa forme décimale ou entière à l'aide des deux méthodes suivantes :
2.
3.
valeur_dec =
spin_button.get_value
(
)
valeur_ent =
spin_button.get_value_as_int
(
)
Si l'on souhaite que la modification de la valeur soit effectuée par rapport à la valeur courante, on peut utiliser cette méthode :
boite_increment.spin
(
direction, increment)
Le paramètre direction peut prendre l'une de ces valeurs :
2.
3.
4.
5.
6.
7.
SPIN_STEP_FORWARD
SPIN_STEP_BACKWARD
SPIN_PAGE_FORWARD
SPIN_PAGE_BACKWARD
SPIN_HOME
SPIN_END
SPIN_USER_DEFINED
Cette méthode réunit plusieurs fonctionnalités que nous allons tenter d'expliquer clairement. Un grand nombre de ces réglages utilise les valeurs de l'ajustementChapitre 7. Les ajustements associées à la boîte d'incrément.
SPIN_STEP_FORWARD (en avant d'un pas) et SPIN_STEP_BACKWARD (en arrière d'un pas) modifient la valeur de la boîte d'incrément en lui ajoutant/soustrayant celle spécifiée par l'argument increment, ou, si ce dernier vaut 0, celle du step_increment de l'ajustementChapitre 7. Les ajustements.
SPIN_PAGE_FORWARD (en avant d'une page) et SPIN_PAGE_BACKWARD (en arrière d'une page) modifient simplement la valeur de la boîte d'incrément en lui ajoutant/soustrayant celle de increment.
SPIN_HOME (début) fixe la valeur de la boîte d'incrément à la borne minimum de l'intervalle de l'ajustementChapitre 7. Les ajustements.
SPIN_END (fin) fixe la valeur de la boîte d'incrément à la borne maximum de l'intervalle de l'ajustementChapitre 7. Les ajustements.
SPIN_USER_DEFINED (défini par l'utilisateur) modifie simplement la valeur de la boîte d'incrément en lui ajoutant la valeur spécifiée.
Abandonnons à présent les méthodes de définition et récupération des attributs d'intervalle, pour nous intéresser à celles qui affectent l'apparence et le comportement du widget gtk.SpinButton en lui-même.
La première de ces méthodes sert à faire en sorte que la boîte de texte du gtk.SpinButton ne puisse contenir que des valeurs numériques. L'utilisateur ne pourra alors pas y saisir autre chose :
boite_increment.set_numeric
(
numeric)
Si numeric vaut TRUE (vrai), le champ de saisie n'acceptera que les valeurs numériques. Si elles vaut FALSE (faux), aucune contrainte n'est posée.
On peut indiquer si l'on veut que la boîte d'incrément effectue une boucle après avoir passé la valeur maximum de l'intervalle, et revienne donc à la valeur minimum. On utilisera pour ce faire la méthode suivante :
boite_increment.set_wrap
(
wrap)
La boîte d'incrément tournera en boucle si wrap vaut TRUE.
On peut faire en sorte que la boîte d'incrément arrondisse la valeur au step_increment le plus proche (le step_increment est défini dans l'ajustementChapitre 7. Les ajustements utilisé par la boîte d'incrément). On fera alors appel à la méthode suivante, où snap_to_ticks (s'accrocher aux marques) devra valoir TRUE :
boite_increment.set_snap_to_ticks
(
snap_to_ticks)
Le mode d'actualisation d'une boîte d'incrément peut être modifié avec la méthode suivante :
boite_increment.set_update_policy
(
policy)
Les valeurs possibles pour policy (mode) sont :
2.
3.
UPDATE_ALWAYS
UPDATE_IF_VALID
Ces modes d'actualisation affectent le comportement de la boîte d'incrément lorsqu'elle analyse le texte saisi et qu'elle synchronise sa valeur avec celles de l'ajustementChapitre 7. Les ajustements.
Avec UPDATE_IF_VALID (actualiser si valide), la valeur de la boîte d'incrément n'est modifiée que si le texte saisi est une valeur numérique comprise dans l'intervalle de l'ajustementChapitre 7. Les ajustements. Dans le cas contraire, le champ de saisie reprend sa valeur courante.
Avec UPDATE_ALWAYS (actualiser toujours), toute erreur sera ignorée lors de la conversion du texte en valeur numérique.
Pour finir, on peut demander explicitement une actualisation de la boîte d'incrément :
boite_increment.update
(
)
Le programme d'exemple boitesincrement.py offre une démonstration d'utilisation des boîtes d'incrément, incluant la modification de plusieurs caractéristiques. La Figure 9.11 montre ce que l'on obtient en lançant le programme :
Voici le code source de boitesincrement.py :
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.
#
!/usr/bin/env
python
#
exemple
boiteincrement.py
import
pygtk
pygtk.require
(
'
2
.
0
'
)
import
gtk
class
ExempleBoiteIncrement:
def
modif_arrondi
(
self, widget, boiteincr):
boiteincr.set_snap_to_ticks
(
widget.get_active
(
))
def
modif_numerique
(
self, widget, boiteincr):
boiteincr.set_numeric
(
widget.get_active
(
))
def
modif_decimales
(
self, widget, boiteincr, boiteincr1):
boiteincr1.set_digits
(
boiteincr.get_value_as_int
(
))
def
recup_valeur
(
self, widget, donnees, boiteincr, boiteincr2, etiquette):
if
donnees =
=
1
:
tampon =
"
%d
"
%
boiteincr.get_value_as_int
(
)
else
:
tampon =
"
%
0
.
*
f
"
%
(
boiteincr2.get_value_as_int
(
),
boiteincr.get_value
(
))
etiquette.set_text
(
tampon)
def
__init__
(
self):
fenetre =
gtk.Window
(
gtk.WINDOW_TOPLEVEL)
fenetre.connect
(
"
destroy
"
, gtk.main_quit)
fenetre.set_title
(
"
Boîtes
d
'
increment
"
)
boite_v0 =
gtk.VBox
(
False
, 5
)
boite_v0.set_border_width
(
10
)
fenetre.add
(
boite_v0)
cadre =
gtk.Frame
(
"
Sans
accélération
"
)
boite_v0.pack_start
(
cadre, True
, True
, 0
)
boite_v1 =
gtk.VBox
(
False
, 0
)
boite_v1.set_border_width
(
5
)
cadre.add
(
boite_v1)
#
Boîtes
d'incrément
pour
le
jour,
le
mois
et
l'année
boite_h =
gtk.HBox
(
False
, 0
)
boite_v1.pack_start
(
boite_h, True
, True
, 5
)
boite_v2 =
gtk.VBox
(
False
, 0
)
boite_h.pack_start
(
boite_v2, True
, True
, 5
)
etiquette =
gtk.Label
(
"
Jour
:
"
)
etiquette.set_alignment
(
0
, 0.5
)
boite_v2.pack_start
(
etiquette, False
, True
, 0
)
ajustement =
gtk.Adjustment
(
1.0
, 1.0
, 31.0
, 1.0
, 5.0
, 0.0
)
boiteincr =
gtk.SpinButton
(
ajustement, 0
, 0
)
boiteincr.set_wrap
(
True
)
boite_v2.pack_start
(
boiteincr, False
, True
, 0
)
boite_v2 =
gtk.VBox
(
False
, 0
)
boite_h.pack_start
(
boite_v2, True
, True
, 5
)
etiquette =
gtk.Label
(
"
Mois
:
"
)
etiquette.set_alignment
(
0
, 0.5
)
boite_v2.pack_start
(
etiquette, False
, True
, 0
)
ajustement =
gtk.Adjustment
(
1.0
, 1.0
, 12.0
, 1.0
, 5.0
, 0.0
)
boiteincr =
gtk.SpinButton
(
ajustement, 0
, 0
)
boiteincr.set_wrap
(
True
)
boite_v2.pack_start
(
boiteincr, False
, True
, 0
)
boite_v2 =
gtk.VBox
(
False
, 0
)
boite_h.pack_start
(
boite_v2, True
, True
, 5
)
etiquette =
gtk.Label
(
"
Annee
:
"
)
etiquette.set_alignment
(
0
, 0.5
)
boite_v2.pack_start
(
etiquette, False
, True
, 0
)
ajustement =
gtk.Adjustment
(
1998.0
, 0.0
, 2100.0
, 1.0
, 100.0
, 0.0
)
boiteincr =
gtk.SpinButton
(
ajustement, 0
, 0
)
boiteincr.set_wrap
(
False
)
boiteincr.set_size_request
(
55
, -
1
)
boite_v2.pack_start
(
boiteincr, False
, True
, 0
)
cadre =
gtk.Frame
(
"
Avec
accélération
"
)
boite_v0.pack_start
(
cadre, True
, True
, 0
)
boite_v1 =
gtk.VBox
(
False
, 0
)
boite_v1.set_border_width
(
5
)
cadre.add
(
boite_v1)
boite_h =
gtk.HBox
(
False
, 0
)
boite_v1.pack_start
(
boite_h, False
, True
, 5
)
boite_v2 =
gtk.VBox
(
False
, 0
)
boite_h.pack_start
(
boite_v2, True
, True
, 5
)
etiquette =
gtk.Label
(
"
Valeur
:
"
)
etiquette.set_alignment
(
0
, 0.5
)
boite_v2.pack_start
(
etiquette, False
, True
, 0
)
ajustement =
gtk.Adjustment
(
0.0
, -
10000.0
, 10000.0
, 0.5
, 100.0
, 0.0
)
boiteincr1 =
gtk.SpinButton
(
ajustement, 1.0
, 2
)
boiteincr1.set_wrap
(
True
)
boiteincr1.set_size_request
(
100
, -
1
)
boite_v2.pack_start
(
boiteincr1, False
, True
, 0
)
boite_v2 =
gtk.VBox
(
False
, 0
)
boite_h.pack_start
(
boite_v2, True
, True
, 5
)
etiquette =
gtk.Label
(
"
Décimales
:
"
)
etiquette.set_alignment
(
0
, 0.5
)
boite_v2.pack_start
(
etiquette, False
, True
, 0
)
ajustement =
gtk.Adjustment
(
2
, 1
, 5
, 1
, 1
, 0
)
boiteincr2 =
gtk.SpinButton
(
ajustement, 0.0
, 0
)
boiteincr2.set_wrap
(
True
)
ajustement.connect
(
"
value_changed
"
, self.modif_decimales, boiteincr2, boiteincr1)
boite_v2.pack_start
(
boiteincr2, False
, True
, 0
)
boite_h =
gtk.HBox
(
False
, 0
)
boite_v1.pack_start
(
boite_h, False
, True
, 5
)
bouton =
gtk.CheckButton
(
"
Déplacement
tous
les
0
,
5
"
)
bouton.connect
(
"
clicked
"
, self.modif_arrondi, boiteincr1)
boite_v1.pack_start
(
bouton, True
, True
, 0
)
bouton.set_active
(
True
)
bouton =
gtk.CheckButton
(
"
Saisie
numérique
seulement
"
)
bouton.connect
(
"
clicked
"
, self.modif_numerique, boiteincr1)
boite_v1.pack_start
(
bouton, True
, True
, 0
)
bouton.set_active
(
True
)
etiquette_valeur =
gtk.Label
(
"
"
)
boite_h =
gtk.HBox
(
False
, 0
)
boite_v1.pack_start
(
boite_h, False
, True
, 5
)
bouton =
gtk.Button
(
"
Valeur
entiere
"
)
bouton.connect
(
"
clicked
"
, self.recup_valeur, 1
, boiteincr1, boiteincr2,
etiquette_valeur)
boite_h.pack_start
(
bouton, True
, True
, 5
)
bouton =
gtk.Button
(
"
Valeur
decimale
"
)
bouton.connect
(
"
clicked
"
, self.recup_valeur, 2
, boiteincr1, boiteincr2,
etiquette_valeur)
boite_h.pack_start
(
bouton, True
, True
, 5
)
boite_v1.pack_start
(
etiquette_valeur, True
, True
, 0
)
etiquette_valeur.set_text
(
"
0
"
)
boite_h =
gtk.HBox
(
False
, 0
)
boite_v0.pack_start
(
boite_h, False
, True
, 0
)
bouton =
gtk.Button
(
"
Fermer
"
)
bouton.connect
(
"
clicked
"
, gtk.main_quit)
boite_h.pack_start
(
bouton, True
, True
, 5
)
fenetre.show_all
(
)
def
main
(
):
gtk.main
(
)
return
0
if
__name__
=
=
"
__main__
"
:
ExempleBoiteIncrement
(
)
main
(
)
9-11. Les listes déroulantes▲
L'utilisation du widget gtk.Combo n'est plus recommandée depuis PyGTK 2.4.
La liste déroulante est un autre widget très simple, qui n'est en fait qu'une association d'autres widgets. Du point de vue de l'utilisateur, il s'agit d'un champ de saisie, accompagné d'un menu déroulant qui permet à l'utilisateur d'effectuer un choix parmi un ensemble d'entrées prédéfinies. L'utilisateur peut également taper directement une autre option dans le champ de saisie.
Les deux parties qui nous intéressent réellement dans le widget gtk.Combo sont le champ de saisie (appelé entry) et la liste (list). On peut accéder y en utilisant les attributs suivants :
2.
3.
listder.entry
listeder.list
Pour commencer, on créera une liste déroulante ainsi :
listeder =
gtk.Combo
(
)
Maintenant, si l'on souhaite définir la chaîne de caractères du champ de saisie, la manipulation doit se faire directement sur ce dernier :
listeder.entry.set_text
(
text)
Pour définir les valeurs de la liste, on utilise la méthode suivante :
listeder.set_popdown_strings
(
strings)
Mais avant, il faudra créer une liste regroupant les chaînes de caractères que l'on veut.
Voici un segment de code typique pour créer un ensemble d'options :
2.
3.
listechaines =
[ "
Chaine
1
"
, "
Chaine
2
"
, "
Chaine
3
"
, "
Chaine
4
"
]
listeder.set_popdown_strings
(
listechaines)
Arrivé ici, on a configuré une liste déroulante fonctionnelle. Quelques aspects de son comportement peuvent encore être modifiés, et ce par l'intermédiaire des méthodes qui suivent :
2.
3.
4.
5.
listeder.set_use_arrows
(
val)
listeder.set_use_arrows_always
(
val)
listeder.set_case_sensitive
(
val)
La méthode set_use_arrows() laissera l'utilisateur modifier la valeur du champ de saisie avec les touches de déplacement haut et bas du clavier si val vaut TRUE. Cela ne fera pas apparaître la liste, mais remplacera le texte courant du champ de saisie par l'entrée suivante ou précédente dans la liste (en fonction de la touche pressée). La méthode déclenche en effet une recherche, dans cette liste, de l'entrée qui correspond à la valeur du champ de saisie, puis sélectionne l'entrée qui la suit ou la précède. Dans un champ de saisie, les touches de déplacement du clavier servent habituellement à changer la zone active (on peut quand même le faire avec TAB). Notez que lorsque l'élément courant est le dernier élément de la liste, une pression sur la touche de déplacement vers le bas changera de zone active (idem pour le premier élément avec la touche de déplacement vers le haut).
Si la valeur courante du champ de saisie ne figure pas dans la liste, la méthode set_use_arrows() est désactivée.
La méthode set_use_arrows_always() permet également, si val vaut TRUE, l'utilisation des touches de déplacement pour passer d'une entrée de la liste déroulante à une autre. Toutefois, elle désactive complètement les fonctions de changement de zone active des touches de déplacement. Les valeurs de la liste tournent alors en boucle.
La méthode set_case_sensitive() détermine si GTK doit prendre en compte la casse des caractères lors des recherches d'entrées dans la liste. Cela sert lorsque l'on demande au gtk.Combo de trouver une valeur dans la liste à partir du texte entré dans le champ de saisie. Cette sorte de complétion peut se réaliser en prenant la casse en compte ou pas, en fonction de ce qu'indique la méthode. Le gtk.Combo peut aussi simplement compléter le texte du champ de saisie si l'utilisateur presse la combinaison de touches MOD-1-Tab. MOD-1 est souvent associé à la touche Alt par l'utilitaire xmodmap. Notez, cependant, que certains gestionnaires de fenêtres utilisent eux aussi cette combinaison, et que dans ce cas ils l'emportent sur GTK.
Maintenant que nous disposons d'une liste déroulante taillée sur mesure, il ne nous reste plus qu'à pouvoir en obtenir des données. C'est relativement simple. La plupart du temps, les seules données que l'on souhaitera récupérer seront celles du champ de saisie, le combo.entry. On pourra vouloir lui connecter le signal "activate" (qui indique que l'utilisateur a pressé la touche Entrée), ou bien lire le texte. Dans le premier cas, on utilisera quelque chose comme ceci :
listeder.entry.connect
(
"
activate
"
, fct_rappel, donnees)
Quant à la récupération du texte, elle s'effectue simplement, et à n'importe quel moment, par un appel à la méthode du champ de saisie suivante :
chaine =
listeder.entry.get_text
(
)
Voilà, c'est à peu près tout ce qu'il y a à savoir. Il y a bien cette méthode :
listeder.disable_activate
(
)
qui désactive le signal "activate" pour le champ de saisie. Personnellement, je ne vois pas pourquoi l'on voudrait s'en servir, mais bon, elle existe.
9-12. Le calendrier▲
Le widget gtk.Calendar est un moyen efficace pour afficher et récupérer des informations calendaires organisées par mois. Il s'agit d'un widget très simple à créer et à utiliser.
Pour créer un calendrier, il suffit d'utiliser la méthode suivante :
calendrier =
gtk.Calendar
(
)
Par défaut, le calendrier affiche le mois et l'année courants.
On pourra parfois avoir besoin de modifier plusieurs données de ce widget ; les méthodes qui suivent permettront d'apporter un grand nombre de modifications au calendrier, ceci sans que l'utilisateur n'ait à voir son affichage s'actualiser à chacune d'elles.
2.
3.
calendrier.freeze
(
)
calendrier.thaw
(
)
Le fonctionnement est exactement le même que pour les méthodes de gel (freeze) et de dégel (thaw) de tout autre widget.
Le calendrier dispose de quelques options permettant de changer son aspect et son comportement. On y accède par l'intermédiaire de la méthode suivante :
calendrier.display_options
(
flags)
L'argument flags (drapeaux) peut comporter n'importe lesquelles des cinq options suivantes, combinées le cas échéant avec l'opérateur de manipulation de bits OR (|) :
CALENDAR_SHOW_HEADING |
Cette option spécifie que le mois et l'année doivent apparaître dans l'affichage du calendrier. |
CALENDAR_SHOW_DAY_NAMES |
Cette option spécifie que des désignations à trois lettres doivent être affichées pour chaque jour (lun, mar, etc.). |
CALENDAR_NO_MONTH_CHANGE |
Cette option spécifie que l'utilisateur ne doit pas pouvoir afficher d'autre mois que celui qui est affiché. Cela peut être utile lorsque on ne souhaite afficher qu'un seul mois précis, par exemple dans le cas où l'on affiche 12 calendriers, un pour chaque mois d'une année donnée. |
CALENDAR_SHOW_WEEK_NUMBERS |
Cette option spécifie que le numéro de chaque semaine doit être affiché sur la gauche du calendrier (1er Jan = Semaine 1, 31 Déc = Semaine 52). |
CALENDAR_WEEK_START_MONDAY |
Cette option spécifie que la semaine du calendrier commence le lundi, et non pas le dimanche (réglage par défaut). Seul est affecté l'ordre dans lequel sont affichés les jours de gauche à droite. |
On utilise les méthodes suivantes pour définir la date affichée :
2.
3.
resultat =
calendrier.select_month
(
month, year)
calendrier.select_day
(
day)
La méthode select_month() renvoie une valeur booléenne indiquant si la sélection s'est déroulée avec succès.
Avec la méthode select_day(), le numéro de jour spécifié se voit sélectionné dans le mois courant, dans la mesure du possible. Un numéro de jour de 0 aura pour effet d'invalider toute sélection courante.
Outre le fait qu'un jour du mois puisse être sélectionné, chacun des autres jours peut être "marqué", c'est-à-dire mis en relief dans l'affichage du calendrier. On se servira des méthodes suivantes pour manipuler les jours marqués :
2.
3.
4.
5.
resultat =
calendrier.mark_day
(
day) #
marquer
un
jour
resultat =
calendrier.unmark_day
(
day) #
démarquer
un
jour
calendrier.clear_marks
(
) #
enlever
toutes
les
marques
mark_day() et unmark_day() renvoient une valeur booléenne indiquant si l'opération s'est déroulée avec succès. Notez que les marques sont conservées même lors de changements de mois ou d'année.
La dernière méthode du calendrier permet de récupérer la date, le mois et l'année sélectionnés.
année, mois, jour =
calendrier.get_date
(
)
Le widget gtk.Calendar peut générer un certain nombre de signaux indiquant un changement ou une sélection de date. En voici une liste :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
month_changed #
mois
changé
day_selected #
jour
sélectionné
day_selected_double_click #
jour
séectionné
double-clic
prev_month #
mois
précédent
next_month #
mois
suivant
prev_year #
année
précédente
next_year #
année
suivante
Il ne nous reste plus qu'à rassembler tout ceci dans le programme exemple calendrier.py. La Figure 9.12 montre le résultat du programme :
Voici le code source de calendrier.py :
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.
#
!/usr/bin/env
python
#
exemple
calendrier.py
#
#
Copyright
(C)
1998
Cesar
Miquel,
Shawn
T.
Amundson,
Mattias
Gronlund
#
Copyright
(C)
2000
Tony
Gale
#
Copyright
(C)
2001-2002
John
Finlay
#
#
This
program
is
free
software;
you
can
redistribute
it
and/or
modify
#
it
under
the
terms
of
the
GNU
General
Public
License
as
published
by
#
the
Free
Software
Foundation;
either
version
2
of
the
License,
or
#
(at
your
option)
any
later
version.
#
#
This
program
is
distributed
in
the
hope
that
it
will
be
useful,
#
but
WITHOUT
ANY
WARRANTY;
without
even
the
implied
warranty
of
#
MERCHANTABILITY
or
FITNESS
FOR
A
PARTICULAR
PURPOSE.
See
the
#
GNU
General
Public
License
for
more
details.
#
#
You
should
have
received
a
copy
of
the
GNU
General
Public
License
#
along
with
this
program;
if
not,
write
to
the
Free
Software
#
Foundation,
Inc.,
675
Mass
Ave,
Cambridge,
MA
02139,
USA.
import
pygtk
pygtk.require
(
'
2
.
0
'
)
import
gtk, pango
import
time
class
ExempleCalendrier:
DEF_ESP =
10
DEF_PETIT_ESP =
5
ANNEE_BASE =
1900
calendrier_affich_entete =
0
calendrier_affich_jours =
1
calendrier_change_mois =
2
calendrier_affich_semaine =
3
def
calendrier_date_chaine
(
self):
annee, mois, jour =
self.fenetre.get_date
(
)
date =
time.mktime
(
(
annee, mois+
1
, jour, 0
, 0
, 0
, 0
, 0
, -
1
))
return
time.strftime
(
"
%x
"
, time.localtime
(
date))
def
calendrier_chaines_signaux
(
self, chaine_signal):
penult_sig =
self.penult_sig.get
(
)
self.apenult_sig.set_text
(
penult_sig)
penult_sig =
self.dern_sig.get
(
)
self.penult_sig.set_text
(
penult_sig)
self.dern_sig.set_text
(
chaine_signal)
def
calendrier_change_mois
(
self, widget):
tampon =
"
month_changed
:
%s
"
%
self.calendrier_date_chaine
(
)
self.calendrier_chaines_signaux
(
tampon)
def
calendrier_selec_jour
(
self, widget):
tampon =
"
day_selected
:
%s
"
%
self.calendrier_date_chaine
(
)
self.calendrier_chaines_signaux
(
tampon)
def
calendrier_selec_jour_dbleclic
(
self, widget):
tampon =
"
day_selected_double_click
:
%s
"
tampon =
tampon %
self.calendrier_date_chaine
(
)
self.calendrier_chaines_signaux
(
tampon)
annee, mois, jour =
self.fenetre.get_date
(
)
if
self.date_marquee[jour-
1
] =
=
0
:
self.fenetre.mark_day
(
jour)
self.date_marquee[jour-
1
] =
1
else
:
self.fenetre.unmark_day
(
jour)
self.date_marquee[jour-
1
] =
0
def
calendrier_mois_prec
(
self, widget):
tampon =
"
prev_month
:
%s
"
%
self.calendrier_date_chaine
(
)
self.calendrier_chaines_signaux
(
tampon)
def
calendrier_mois_suiv
(
self, widget):
tampon =
"
next_month
:
%s
"
%
self.calendrier_date_chaine
(
)
self.calendrier_chaines_signaux
(
tampon)
def
calendrier_annee_prec
(
self, widget):
tampon =
"
prev_year
:
%s
"
%
self.calendrier_date_chaine
(
)
self.calendrier_chaines_signaux
(
tampon)
def
calendrier_annee_suiv
(
self, widget):
tampon =
"
next_year
:
%s
"
%
self.calendrier_date_chaine
(
)
self.calendrier_chaines_signaux
(
tampon)
def
calendrier_def_drapeaux
(
self):
options =
0
for
i in
range(
5
):
if
self.reglages[i]:
options =
options +
(
1
<
9-13. Le sélecteur de couleur▲
Le sélecteur de couleur est, on l'aura deviné, un widget permettant une sélection interactive des couleurs. Ce widget composite permet à l'utilisateur de choisir une couleur en manipulant des triplets RVB (Rouge, Vert, Bleu) ou TSV (Teinte, Saturation, Valeur). Chacune des valeurs peut être ajustée à l'aide de gradateurs ou de champs de saisie, ou bien en désignant directement la couleur désirée dans une roue de teinte-saturation/barre de valeur. Il est également possible de définir l'opacité de la couleur.
Le sélecteur de couleur ne dispose actuellement que d'un seul signal, "color_changed". Il est émis à chaque modification de la couleur courante dans le widget, qu'elle vienne de l'utilisateur ou bien d'une définition explicite par la méthode set_color().
Observons à présent ce que peut nous offrir ce widget. Il est proposé sous deux formes : gtk.ColorSelection et gtk.ColorSelectionDialog.
selectcouleur =
gtk.ColorSelection
(
)
Vous n'aurez probablement pas à utiliser ce constructeur directement. Il crée un gtk.ColorSelection orphelin auquel vous devrez affecter un parent vous-même. Le widget gtk.ColorSelection hérite du widget gtk.VBox.
dialselectcouleur =
gtk.ColorSelectionDialog
(
title)
title (titre) est une chaîne de caractères à utiliser pour la barre de titre de la boîte de dialogue.
Il s'agit là du constructeur le plus courant pour les sélecteurs de couleur. Il crée un gtk.ColorSelectionDialog, qui consiste en un cadre (gtk.Frame) contenant un gtk.ColorSelection, un séparateur horizontal, ainsi qu'une boîte horizontale possédant trois boutons : "Ok", "Cancel" et "Help". Ces derniers sont accessibles par les attributs ok_button, cancel_button et help_button du ColorSelectionDialog (ex. : dialselectcouleur.ok_button). Pour accéder au sélecteur de couleur en lui-même, on utilisera l'attribut colorsel :
selectcouleur =
dialselectcouleur.colorsel
Le widget gtk.ColorSelection dispose de plusieurs méthodes qui changent ses caractéristiques ou permettent d'accéder à la sélection de couleur.
selectcouleur.set_has_opacity_control
(
has_opacity)
Le sélecteur de couleur permet de régler l'opacité d'une couleur (aussi appelée canal alpha). Cette option est désactivée par défaut. Pour autoriser les réglages d'opacité, il faut appeler la méthode ci-dessus en donnant la valeur TRUE à son argument has_opacity. Inversement, l'appeler avec FALSE interdira cette possibilité.
selectcouleur.set_current_color
(
color)
selectcouleur.set_current_alpha
(
alpha)
On peut définir explicitement la couleur courante en appelant la méthode set_current_color() avec une GdkColor. Le réglage d'opacité (le canal alpha) s'effectue avec la méthode set_current_alpha(). La valeur alpha doit être comprise entre 0 (transparence totale) et 65 636 (opacité totale).
couleur =
selectcouleur.get_current_color
(
)
alpha =
selectcouleur.get_current_alpha
(
)
Pour récupérer la couleur courante, généralement lors de la réception d'un signal "color_changed", on utilise ces méthodes.
Le programme selectcouleur.py donne un exemple d'utilisation du gtk.ColorSelectionDialog. Le programme affiche une fenêtre contenant une zone de dessin qui, si elle est cliquée, ouvre une boîte de dialogue de sélection de couleur. Les modifications de couleur effectuées dans cette boîte de dialogue entraînent le changement de la couleur d'arrière-plan de la zone de dessin. La Figure 9.13 montre ce programme en exécution :
Le code source de selectcouleur.py est le suivant :
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.
#
!/usr/bin/env
python
#
exemple
selectcouleur.py
import
pygtk
pygtk.require
(
'
2
.
0
'
)
import
gtk
class
ExempleSelecteurCouleur:
#
Gestionnaire
du
signal
"color_changed"
def
rappel_color_changed
(
self, widget):
#
On
récupère
la
table
des
couleurs
de
la
zone
de
dessin
tablecouleurs =
self.zonedessin.get_colormap
(
)
#
On
récupère
la
couleur
courante
couleur =
self.dialselectcouleur.colorsel.get_current_color
(
)
#
On
définit
la
couleur
d'arrière-plan
de
la
fenêtre
self.zonedessin.modify_bg
(
gtk.STATE_NORMAL, couleur)
#
Gestionnaire
d'évènement
de
la
zone
de
dessin
def
evnmt_zone
(
self, widget, evnmt):
prisencharge =
False
#
On
vérifie
si
on
a
reçu
un
évènement
"button-press"
if
evnmt.type =
=
gtk.gdk.BUTTON_PRESS:
prisencharge =
True
#
Création
de
la
boîte
de
dialogue
du
sélecteur
de
couleur
if
self.dialselectcouleur =
=
None
:
self.dialselectcouleur =
gtk.ColorSelectionDialog
(
"
Selection
de
la
couleur
d
'
arriere
-
plan
"
)
#
On
récupère
le
sélecteur
de
couleur
selectcouleur =
self.dialselectcouleur.colorsel
selectcouleur.set_previous_color
(
self.couleur)
selectcouleur.set_current_color
(
self.couleur)
selectcouleur.set_has_palette
(
True
)
#
Connexion
au
signal
"color_changed"
selectcouleur.connect
(
"
color_changed
"
, self.rappel_color_changed)
#
Affichage
de
la
boîte
de
dialogue
reponse =
self.dialselectcouleur.run
(
)
if
reponse -
-
gtk.RESPONSE_OK:
self.couleur =
selectcouleur.get_current_color
(
)
else
:
self.zonedessin.modify_bg
(
gtk.STATE_NORMAL, self.couleur)
self.dialselectcouleur.hide
(
)
return
prisencharge
#
Fermeture
et
sortie
du
gestionnaire
def
destruct_fenetre
(
self, widget, evnmt):
gtk.main_quit
(
)
return
True
def
__init__
(
self):
self.dialselectcouleur =
None
#
Création
d'une
fenêtre
racine
+
titre
+
modes
fenetre =
gtk.Window
(
gtk.WINDOW_TOPLEVEL)
fenetre.set_title
(
"
Test
de
sélection
de
couleur
"
)
fenetre.set_resizable
(
True
)
#
Connexion
aux
évènements
"delete"
et
"destroy"
pour
pouvoir
sortir
fenetre.connect
(
"
delete_event
"
, self.destruct_fenetre)
#
Création
de
la
zone
de
dessin
+
taille
+
recup
evnmts
des
boutons
self.zonedessin =
gtk.DrawingArea
(
)
self.couleur =
self.zonedessin.get_colormap
(
).alloc_color
(
0
, 65535
, 0
)
self.zonedessin.set_size_request
(
200
, 200
)
self.zonedessin.set_events
(
gtk.gdk.BUTTON_PRESS_MASK)
self.zonedessin.connect
(
"
event
"
, self.evnmt_zone)
#
Ajout
de
la
zone
de
dessin
a
la
fenêtre,
puis
affichage
des
deux
fenetre.add
(
self.zonedessin)
self.zonedessin.show
(
)
fenetre.show
(
)
def
main
(
):
gtk.main
(
)
return
0
if
__name__
=
=
"
__main__
"
:
ExempleSelecteurCouleur
(
)
main
(
)
9-14. Le sélecteur de fichier▲
Le sélecteur de fichier est un moyen simple et rapide d'afficher une boîte de dialogue de fichier déjà équipée des boutons Valider, Annuler et Aide. Une bonne économie en temps de programmation !
Pour créer une nouvelle boîte de sélection de fichier, on utilise :
selectfichier =
gtk.FileSelection
(
title=
None
)
Pour définir le nom du fichier, par exemple pour joindre directement un dossier spécifique ou donner un nom de fichier par défaut, on utilise la méthode :
selectfichier.set_filename
(
filename)
où filename est le nom du fichier. Pour récupérer, sous forme de texte, le nom du fichier que l'utilisateur a saisi ou cliqué, on fait appel à la méthode suivante :
nomfichier =
selectfichier.get_filename
(
)
Il existe aussi des références aux widgets contenus dans le sélecteur de fichier. Ce sont tous des attributs de selectfichier :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
selectfichier.dir_list #
(liste
des
dossiers)
selectfichier.file_list #
(liste
des
fichiers)
selectfichier.selection_entry #
(champ
de
saisie
"Sélection")
selectfichier.selection_text #
(texte
"Sélection")
selectfichier.main_vbox #
(boîte
verticale
principale)
selectfichier.ok_button #
(bouton
Valider)
selectfichier.cancel_button #
(bouton
Annuler)
selectfichier.help_button #
(bouton
Aide)
selectfichier.history_pulldown #
(menu
historique
déroulant)
selectfichier.history_menu #
selectfichier.fileop_dialog #
(boutons
d'opération
sur
fichier
:
boîte
de
dialogue)
selectfichier.fileop_entry #
(boutons
d'opération
sur
fichier
:
champ
de
saisie)
selectfichier.fileop_file #
(boutons
d'opération
sur
fichier
:
fichier)
selectfichier.fileop_c_dir #
(boutons
d'opération
sur
fichier
:
bouton
"Créer
un
dossier")
selectfichier.fileop_del_file #
(boutons
d'opération
sur
fichier
:
bouton
"Supprimer
le
fichier")
selectfichier.fileop_ren_file #
(boutons
d'opération
sur
fichier
:
bouton
"Renommer
le
fichier")
selectfichier.button_area #
(zone
des
boutons
d'opération
sur
fichier)
selectfichier.action_area #
On utilisera le plus souvent les attributs ok_button, cancel_button et help_button afin de connecter les signaux de leur widget à des fonctions de rappel.
Le programme selectfichier.py donne un exemple d'utilisation du widget de sélection de fichier. Notez que, bien que le bouton Aide apparaisse à l'écran, il n'a aucun effet, car aucun signal ne lui est attaché. La Figure 9.14 montre l'affichage obtenu :
Le code source de selectfichier.py est le suivant :
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.
#
!/usr/bin/env
python
#
exemple
selectfichier.py
import
pygtk
pygtk.require
(
'
2
.
0
'
)
import
gtk
class
ExempleSelecteurFichier:
#
On
récupère
le
nom
du
fichier
choisi
et
on
l'affiche
dans
la
console
def
ok_fichier
(
self, w):
print
"
%s
"
%
self.selectfichier.get_filename
(
)
def
destroy
(
self, widget):
gtk.main_quit
(
)
def
__init__
(
self):
#
Création
d'un
nouveau
widget
de
sélection
de
fichier
self.selectfichier =
gtk.FileSelection
(
"
Sélection
de
fichier
"
)
self.selectfichier.connect
(
"
destroy
"
, self.destroy)
#
Connexion
du
bouton
OK
à
la
méthode
ok_fichier()
self.selectfichier.ok_button.connect
(
"
clicked
"
, self.ok_fichier)
#
Connexion
du
bouton
Annuler
à
la
destruction
du
widget
self.selectfichier.cancel_button.connect
(
"
clicked
"
,
lambda
w: self.selectfichier.destroy
(
))
#
Définissons
le
fichier,
comme
s'il
s'agissait
d'une
boîte
de
dialogue
#
d'enregistrement
de
fichier
et
que
nous
donnions
un
fichier
par
défaut
self.selectfichier.set_filename
(
"
pingouin
.
png
"
)
self.selectfichier.show
(
)
def
main
(
):
gtk.main
(
)
return
0
if
__name__
=
=
"
__main__
"
:
ExempleSelecteurFichier
(
)
main
(
)
9-15. Le sélecteur de police▲
Le gtk.FontSelectionDialog permet à l'utilisateur de sélectionner interactivement une police pour le programme. Il s'agit d'une boîte de dialogue contenant un widget gtk.FontSelection et des boutons "Valider" et "Annuler". Un bouton "Appliquer" est également disponible, mais il est caché par défaut. Le sélecteur de fichier permet de choisir parmi les polices système disponibles (les mêmes que celles que l'on obtient avec xlsfonts).
La Figure 9.15 montre la boîte de dialogue du sélecteur de police :
La boîte de dialogue contient un ensemble de trois onglets qui proposent :
- une interface de sélection de la police, de son style et de sa taille ;
- des informations détaillées sur la police sélectionnée ;
- une interface pour le mécanisme de filtrage des polices, qui décide des polices pouvant être sélectionnées.
La fonction de création de cette boîte de dialogue est la suivante :
dialselectpolice =
gtk.FontSelectionDialog
(
title)
Le titre (title) est une chaîne de caractères qui sera utilisée comme texte pour la barre de titre.
Une instance de gtk.FontSelectionDialog possède plusieurs attributs :
2.
3.
4.
5.
6.
fontsel
main_vbox
action_area
ok_button
apply_button
cancel_button
L'attribut fontsel fait référence au widget de sélection de police, et main_vbox à la boîte verticale contenant ce dernier ainsi que l'"action_area". action_area se réfère à la gtk.HButtonBox qui contient les boutons 'Valider', 'Appliquer' et 'Annuler'. Les attributs ok_button, cancel_button et apply_button se rapportent aux boutons 'Valider', 'Appliquer' et 'Annuler', et peuvent servir à établir des connexions aux signaux de ces derniers. apply_button peut servir à afficher le bouton 'Appliquer'.
Avec la méthode qui suit, on peut définir la police qui doit être initialement affichée dans le sélecteur de police :
dialselectpolice.set_font_name
(
fontname)
L'argument fontname (nom de police) attend le nom d'une police système intégralement ou partiellement spécifiée. Par exemple :
dialselectpolice.set_font_name
(
'
-
adobe
-
courier
-
bold
-
*
-
*
-
*
-
*
-
120
-
*
-
*
-
*
-
*
-
*
-
*
'
)
spécifie partiellement la police initiale.
Le nom de la police sélectionnée peut être récupéré avec cette méthode :
nom_police =
dialselectpolice.get_font_name
(
)
La boîte de dialogue du sélecteur de police dispose d'une zone d'aperçu qui affiche du texte dans la police sélectionnée. Le texte utilisé dans cette zone d'aperçu peut être défini avec la méthode :
dialselectpolice.set_preview_text
(
text)
Le texte de l'aperçu peut être récupéré à l'aide de la méthode suivante :
texte =
dialselectpolice.get_preview_text
(
)
Le programme exemple calendrier.py utilise un gtk.FontSelectionDialog pour la sélection de la police du calendrier. Les lignes 106 à 111 définissent une fonction de rappel qui récupère le nom de la police à partir du sélecteur de police et l'utilise pour définir la police du calendrier. Les lignes 113-132 définissent la méthode qui crée le sélecteur de police, connecte les boutons 'Valider' et 'Annuler' à leur fonction de rappel, et affiche la boîte de dialogue.