VI. Chapitre 6. Les boutons▲
VI-A. Les boutons simples▲
Nous avons pratiquement déjà fait le tour du widget bouton. Il est en effet très simple. Lors de la création d'un bouton avec la fonction gtk.Button(), vous pouvez lui donner une étiquette en lui passant une chaine de caractères. Mais vous pouvez tout aussi bien créer un bouton vierge en ne passant rien à la fonction ; il vous suffira ensuite, si vous le souhaitez, de placer une étiquette ou une image "pixmap" dans ce nouveau bouton. Pour ce faire, créez une nouvelle boite et placez-y vos objets avec l'habituelle pack_start(). Puis, avec add(), placez la boite dans le bouton.
La fonction de création des boutons est la suivante :
bouton =
gtk.Button
(
label=
None
, stock=
None
)
Si l'on donne une chaine de caractères à l'argument label, elle sera affichée sur le bouton. L'argument stock, quant à lui, sert à afficher sur le bouton une icône du stock de GTK ainsi que le texte correspondant. Les éléments du stock sont :
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.
STOCK_DIALOG_INFO
STOCK_DIALOG_WARNING
STOCK_DIALOG_ERROR
STOCK_DIALOG_QUESTION
STOCK_DND
STOCK_DND_MULTIPLE
STOCK_ADD
STOCK_APPLY
STOCK_BOLD
STOCK_CANCEL
STOCK_CDROM
STOCK_CLEAR
STOCK_CLOSE
STOCK_CONVERT
STOCK_COPY
STOCK_CUT
STOCK_DELETE
STOCK_EXECUTE
STOCK_FIND
STOCK_FIND_AND_REPLACE
STOCK_FLOPPY
STOCK_GOTO_BOTTOM
STOCK_GOTO_FIRST
STOCK_GOTO_LAST
STOCK_GOTO_TOP
STOCK_GO_BACK
STOCK_GO_DOWN
STOCK_GO_FORWARD
STOCK_GO_UP
STOCK_HELP
STOCK_HOME
STOCK_INDEX
STOCK_ITALIC
STOCK_JUMP_TO
STOCK_JUSTIFY_CENTER
STOCK_JUSTIFY_FILL
STOCK_JUSTIFY_LEFT
STOCK_JUSTIFY_RIGHT
STOCK_MISSING_IMAGE
STOCK_NEW
STOCK_NO
STOCK_OK
STOCK_OPEN
STOCK_PASTE
STOCK_PREFERENCES
STOCK_PRINT
STOCK_PRINT_PREVIEW
STOCK_PROPERTIES
STOCK_QUIT
STOCK_REDO
STOCK_REFRESH
STOCK_REMOVE
STOCK_REVERT_TO_SAVED
STOCK_SAVE
STOCK_SAVE_AS
STOCK_SELECT_COLOR
STOCK_SELECT_FONT
STOCK_SORT_ASCENDING
STOCK_SORT_DESCENDING
STOCK_SPELL_CHECK
STOCK_STOP
STOCK_STRIKETHROUGH
STOCK_UNDELETE
STOCK_UNDERLINE
STOCK_UNDO
STOCK_YES
STOCK_ZOOM_100
STOCK_ZOOM_FIT
STOCK_ZOOM_IN
STOCK_ZOOM_OUT
Le programme boutons.py donne un exemple d'utilisation de gtk.Button() pour créer un bouton contenant une image et une étiquette. Le code de création de la boite est séparé du reste afin que vous puissiez l'utiliser dans vos programmes. Nous verrons d'autres exemples faisant appel à des images un peu plus loin dans ce tutoriel. La figure 6.1 montre la fenêtre et son bouton qui contient une étiquette et une image "pixmap" :
Voici le code source du programme boutons.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.
#!/usr/bin/env python
# exemple boutons.py
import
pygtk
pygtk.require
(
'2.0'
)
import
gtk
# On crée une boite verticale, on y place une image
# et une étiquette, et on renvoie la boite.
def
boite_xpm_etiquette
(
parent, fichier_xpm, texte_etiquette):
# On crée une boite pour la pixmap et l'étiquette
boite1 =
gtk.HBox
(
False
, 0
)
boite1.set_border_width
(
2
)
# A présent l'image.
image =
gtk.Image
(
)
image.set_from_file
(
fichier_xpm)
# On crée une étiquette pour le bouton.
etiquette =
gtk.Label
(
texte_etiquette)
# On place la pixmap et l'étiquette dans la boite.
boite1.pack_start
(
image, False
, False
, 3
)
boite1.pack_start
(
etiquette, False
, False
, 3
)
image.show
(
)
etiquette.show
(
)
return
boite1
class
Bouton:
# Notre méthode de rappel habituelle.
def
salut
(
self, widget, donnees=
None
):
print
"Salut ! - Clic sur le
%s
."
%
donnees
def
__init__
(
self):
# Création d'une nouvelle fenêtre.
self.fenetre =
gtk.Window
(
gtk.WINDOW_TOPLEVEL)
self.fenetre.set_title
(
"Bouton et image"
)
# C'est une bonne idée de faire ceci pour chaque fenêtre.
self.fenetre.connect
(
"destroy"
, lambda
wid: gtk.main_quit
(
))
self.fenetre.connect
(
"delete_event"
, lambda
a1,a2: gtk.main_quit
(
))
# On fixe la largeur des bordures de la fenêtre.
self.fenetre.set_border_width
(
10
)
# Création d'un nouveau bouton.
bouton =
gtk.Button
(
)
# On connecte le signal "clicked" du bouton à la fonction de rappel
bouton.connect
(
"clicked"
, self.salut, "bouton cool"
)
# Ceci appelle notre fonction de création de boites.
boite1=
boite_xpm_etiquette
(
self.fenetre, "info.xpm"
, "bouton cool"
)
# On place et on affiche tous nos widgets.
bouton.add
(
boite1)
boite1.show
(
)
bouton.show
(
)
self.fenetre.add
(
bouton)
self.fenetre.show
(
)
def
main
(
):
gtk.main
(
)
return
0
if
__name__
==
"__main__"
:
Bouton
(
)
main
(
)
De la ligne 12 à la ligne 32, on définit la fonction boite_xpm_etiquette() qui prend en charge la création d'une boite horizontale avec une bordure de 2 (lignes 14-15), puis on y place une image (lignes 25) et une étiquette (ligne 26).
Aux lignes 32-66, on définit la classe Bouton. La méthode constructeur s'étale de la ligne 38 à la ligne 66 ; elle crée une fenêtre (ligne 39), lui donne un titre (ligne 41), connecte les signaux "delete_event" et "destroy" (lignes 44-45). Puis, à la ligne 51, elle crée le bouton sans étiquette, avant de connecter son signal "clicked" à la méthode de rappel salut() (ligne 54). Enfin, elle appelle la fonction boite_xpm_etiquette() à la ligne 57, afin de créer l'image et l'étiquette qu'elle placera dans le bouton à la ligne 60.
La fonction boite_xpm_etiquette() pourrait être utilisée pour placer des images "pixmap" et des étiquettes dans n'importe quel widget pouvant jouer le rôle de conteneur.
Le widget bouton peut émettre les signaux suivants :
2.
3.
4.
5.
6.
7.
8.
9.
pressed -
émis lorsque le bouton de la souris est enfoncé sur le widget
released -
émis lorsque le bouton de la souris est relâché sur le widget
clicked -
émis lorsque le bouton de la souris est enfoncé puis relâché sur le widget
enter -
émis lorsque le pointeur de la souris arrive sur le widget
leave -
émis lorsque le pointeur de la souris quitte le widget
VI-B. Les boutons à bascule▲
Le bouton à bascule dérive du bouton simple et lui est donc très similaire. Il a cependant ceci de différent qu'il possède deux états et qu'un clic le fait basculer de l'un à l'autre. Lorsqu'il est enfoncé, un clic le fait remonter. Un autre clic et le voilà de nouveau enfoncé.
Les boutons à bascule sont la base des cases à cocher et des boutons radio, ces derniers héritent donc de beaucoup de leurs appels (nous le signalerons le cas échéant).
Création d'un bouton à bascule :
bouton_bascule =
gtk.ToggleButton
(
label=
None
)
Comme vous pouvez l'imaginer, le fonctionnement de cet appel est identique à celui des boutons normaux. Si aucune étiquette n'est spécifiée, le bouton sera vierge. Dans le cas contraire, le texte donné sera inspecté à la recherche de caractères mnémoniques (préfixés par '_').
Pour récupérer l'état d'un bouton à bascule, ainsi que des boutons radio et des cases à cocher, on fait appel à une construction semblable à l'exemple ci-dessous. Elle teste l'état du bouton en invoquant la méthode get_active() de gtk.ToggleButton. Parmi les signaux émis par les boutons à bascule, celui qui nous intéresse est "toggled". Pour vérifier l'état d'un bouton à bascule, on définira alors un gestionnaire de signal qui se chargera de le capter, puis qui accédera aux attributs de l'objet afin de déterminer son état. La fonction de rappel ressemblera à ceci :
2.
3.
4.
5.
def
fct_rappel_bascule
(
widget, donnees):
if
widget.get_active
(
):
# si le contrôle arrive ici, le bouton à bascule est enfoncé
else
:
# si le contrôle arrive ici, le bouton à bascule est relevé
Pour forcer l'état d'un bouton à bascule (et de ses descendants les cases à cocher et les boutons radio) on utilise la méthode :
bouton_bascule.set_active
(
is_active)
La méthode ci-dessus peut être utilisée pour imposer l'état d'un bouton à bascule, et de ses descendants, les cases à cocher et les boutons radio. En donnant les valeurs TRUE ou FALSE à l'argument is_active, on indique que le bouton doit être respectivement enfoncé ou relevé. Lors de sa création, un bouton à bascule est en position relevée (FALSE) par défaut.
Notez que lorsque l'on utilise la méthode set_active() et que l'état est effectivement modifié, les signaux "clicked" et "toggled" sont automatiquement émis par le bouton.
bouton_bascule.get_active
(
)
Cette méthode renvoie l'état actuel du bouton à bascule sous la forme d'une valeur booléenne TRUE/FALSE.
Le programme boutonsbascule.py donne un exemple courant d'utilisation des boutons à bascule. La figure 6.2 montre la fenêtre obtenue, dans laquelle le deuxième bouton est enfoncé :
Voici le code source du programme :
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.
#!/usr/bin/env python
# exemple boutonsbascule.py
import
pygtk
pygtk.require
(
'2.0'
)
import
gtk
class
BoutonsBascule:
# Notre fonction de rappel. Le paramètre "donnees"
# transmis à cette méthode est affiché sur stdout
def
fct_rappel
(
self, widget, donnees=
None
):
print
"Le
%s
a ete
%s
."
%
(
donnees, (
"releve"
, "enfonce"
)[widget.get_active
(
)])
# Cette fonction de rappel quitte le programme
def
evnmt_delete
(
self, widget, evenement, donnees=
None
):
gtk.main_quit
(
)
return
gtk.FALSE
def
__init__
(
self):
# Création d'une nouvelle fenêtre.
self.fenetre =
gtk.Window
(
gtk.WINDOW_TOPLEVEL)
# On définit le titre de la fenêtre.
self.fenetre.set_title
(
"Boutons a bascule"
)
# On définit un gestionnaire de signal pour "delete_event",
# qui quitte GTK immédiatement.
self.fenetre.connect
(
"delete_event"
, self.evnmt_delete)
# On fixe la largeur des bordures de la fenêtre.
self.fenetre.set_border_width
(
20
)
# Création d'une boite verticale.
boite_v =
gtk.VBox
(
True
, 2
)
# On place la VBox dans la fenêtre principale.
self.fenetre.add
(
boite_v)
# Création du premier bouton.
bouton =
gtk.ToggleButton
(
"bouton a bascule 1"
)
# Lorsque l'on change l'état du bouton, la méthode fct_rappel() est
# appelée, avec un pointeur sur "bouton a bascule 1" comme argument.
bouton.connect
(
"toggled"
, self.fct_rappel, "bouton a bascule 1"
)
# Insertion du bouton 1 dans le quart supérieur gauche du tableau.
boite_v.pack_start
(
bouton, True
, True
, 2
)
bouton.show
(
)
# Création du deuxième bouton.
bouton =
gtk.ToggleButton
(
"bouton a bascule 2"
)
# Lorsque l'on change l'état du bouton, la méthode fct_rappel() est
# appelée, avec un pointeur sur "bouton a bascule 2" comme argument.
bouton.connect
(
"toggled"
, self.fct_rappel, "bouton a bascule 2"
)
# Insertion du bouton 2 dans le quart supérieur droit du tableau.
boite_v.pack_start
(
bouton, True
, True
, 2
)
bouton.show
(
)
# Création du bouton "Quitter".
bouton =
gtk.Button
(
"Quitter"
)
# Lorsque l'on clique sur le bouton, la fonction mainquit() est
# appelée et le programme se termine.
bouton.connect
(
"clicked"
, lambda
wid: gtk.main_quit
(
))
# Insertion du bouton "Quitter" dans les deux quarts inférieurs du tableau.
boite_v.pack_start
(
bouton, True
, True
, 2
)
bouton.show
(
)
boite_v.show
(
)
self.fenetre.show
(
)
def
main
(
):
gtk.main
(
)
return
0
if
__name__
==
"__main__"
:
BoutonsBascule
(
)
main
(
)
Les parties intéressantes sont les lignes 12-13, qui définissent la méthode fct_rappel() chargée d'afficher le nom et l'état du bouton à bascule quand celui-ci voit son état modifié, et les lignes 45 et 59, qui connectent le signal "toggled" des deux boutons à cette même méthode.
VI-C. Les cases à cocher▲
Les cases à cocher héritent de nombreuses propriétés et méthodes des boutons à bascule vus précédemment. Leur aspect est cependant différent : il ne s'agit plus de boutons avec du texte à l'intérieur, mais de petits carrés portant le texte à leur droite. Elles servent souvent pour activer/désactiver des options dans les applications.
La méthode de création est semblable à celle des boutons normaux :
case_a_cocher =
gtk.CheckButton
(
label=
None
)
Si l'argument label est fourni, la méthode crée une case à cocher avec une étiquette à son côté. Le texte donné sera inspecté à la recherche de caractères mnémoniques (préfixés par '_').
Les opérations de vérification et de définition de l'état des cases à cocher sont identiques à celles des boutons à bascule.
Le programme casesacocher.py donne un exemple d'utilisation des cases à cocher. La figure 6.3 montre la fenêtre obtenue :
Voici le code source du programme casesacocher.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.
#!/usr/bin/env python
# exemple casesacocher.py
import
pygtk
pygtk.require
(
'2.0'
)
import
gtk
class
Casesacocher:
# Notre fonction de rappel. Le paramètre "donnees"
# transmis a cette méthode est affiché sur stdout
def
fct_rappel
(
self, widget, donnees=
None
):
print
"La
%s
a ete
%s
."
%
(
donnees, (
"desactivee"
, "activee"
)[widget.get_active
(
)])
# Cette fonction de rappel quitte le programme
def
evnmt_delete
(
self, widget, evenement, donnees=
None
):
gtk.main_quit
(
)
return
gtk.FALSE
def
__init__
(
self):
# Création d'une nouvelle fenêtre.
self.fenetre =
gtk.Window
(
gtk.WINDOW_TOPLEVEL)
# On définit le titre de la fenêtre.
self.fenetre.set_title
(
"Cases a cocher"
)
# On définit un gestionnaire de signal pour "delete_event",
# qui quitte GTK immédiatement.
self.fenetre.connect
(
"delete_event"
, self.evnmt_delete)
# On fixe la largeur des bordures de la fenêtre.
self.fenetre.set_border_width
(
20
)
# Création d'une boite verticale.
boite_v =
gtk.VBox
(
True
, 2
)
# On place la VBox dans la fenêtre principale.
self.fenetre.add
(
boite_v)
# Création du premier bouton.
bouton =
gtk.CheckButton
(
"case a cocher 1"
)
# Lorsque l'on change l'état du bouton, la méthode fct_rappel() est
# appelée, avec un pointeur sur "case à cocher 1" comme argument.
bouton.connect
(
"toggled"
, self.fct_rappel, "case a cocher 1"
)
# Insertion du bouton 1 dans le quart supérieur gauche du tableau.
boite_v.pack_start
(
bouton, True
, True
, 2
)
bouton.show
(
)
# Création du deuxième bouton.
bouton =
gtk.CheckButton
(
"case a cocher 2"
)
# Lorsque l'on change l'état du bouton, la méthode fct_rappel() est
# appelée, avec un pointeur sur "case a cocher 2" comme argument.
bouton.connect
(
"toggled"
, self.fct_rappel, "case a cocher 2"
)
# Insertion du bouton 2 dans le quart supérieur droit du tableau.
boite_v.pack_start
(
bouton, True
, True
, 2
)
bouton.show
(
)
# Création du bouton "Quitter".
bouton =
gtk.Button
(
"Quitter"
)
# Lorsque l'on clique sur le bouton, la fonction mainquit() est
# appelée et le programme se termine.
bouton.connect
(
"clicked"
, lambda
wid: gtk.main_quit
(
))
# Insertion du bouton "Quitter" dans les deux quarts inférieurs du tableau.
boite_v.pack_start
(
bouton, True
, True
, 2
)
bouton.show
(
)
boite_v.show
(
)
self.fenetre.show
(
)
def
main
(
):
gtk.main
(
)
return
0
if
__name__
==
"__main__"
:
Casesacocher
(
)
main
(
)
VI-D. Les boutons radio▲
Les boutons radio sont similaires aux cases à cocher, à ceci près qu'on les assemble par groupes, dans lesquels un seul bouton peut être sélectionné/enfoncé à la fois. Ils sont très pratiques pour les parties de vos applications où l'on doit effectuer une sélection parmi une courte liste.
La création d'un nouveau bouton radio s'effectue avec l'appel suivant :
bouton_radio =
gtk.RadioButton
(
group=
None
, label=
None
)
Vous aurez remarqué le nouvel argument group pour cet appel. En effet, pour fonctionner correctement, les boutons radio nécessitent un groupe. Lors du premier appel à gtk.RadioButton(), l'argument group doit valoir None, ce qui créera un nouveau groupe comptant comme seul membre le nouveau bouton radio.
Pour ajouter de nouveaux boutons radio à un groupe, transmettez lors de vos appels à gtk.RadioButton() une référence à un bouton radio du groupe.
Si vous avez spécifié un texte pour l'argument label, il sera passé en revue à la recherche de caractères mnémoniques (préfixés par '_').
Pour définir explicitement le bouton qui doit être sélectionné par défaut, utilisez :
bouton_radio.set_active
(
is_active)
Cette méthode est décrite dans la section sur les boutons à bascule et fonctionne exactement de la même manière. Une fois que les boutons radio sont assemblés en un groupe, on ne pourra sélectionner qu'un seul bouton de ce groupe à la fois. Si l'utilisateur clique sur un bouton radio, puis sur un autre, alors le premier émettra un signal "toggled" pour informer qu'il a été désactivé, avant que le second l'imite, pour signaler cette fois qu'il vient d'être activé.
Le programme exemple boutonsradio.py crée un groupe de trois boutons radio. La figure 6.4 montre la fenêtre obtenue :
Voici le code source du programme :
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.
#!/usr/bin/env python
# exemple boutonsradio.py
import
pygtk
pygtk.require
(
'2.0'
)
import
gtk
class
BoutonsRadio:
def
fct_rappel
(
self, widget, donnees=
None
):
print
"Le
%s
a ete
%s
."
%
(
donnees, (
"desactive"
, "active"
)[widget.get_active
(
)])
def
quitter_pgm
(
self, widget, evenement, donnees=
None
):
gtk.main_quit
(
)
return
False
def
__init__
(
self):
self.fenetre =
gtk.Window
(
gtk.WINDOW_TOPLEVEL)
self.fenetre.connect
(
"delete_event"
, self.quitter_pgm)
self.fenetre.set_title
(
"Boutons radio"
)
self.fenetre.set_border_width
(
0
)
boite1 =
gtk.VBox
(
False
, 0
)
self.fenetre.add
(
boite1)
boite1.show
(
)
boite2 =
gtk.VBox
(
False
, 10
)
boite2.set_border_width
(
10
)
boite1.pack_start
(
boite2, True
, True
, 0
)
boite2.show
(
)
bouton =
gtk.RadioButton
(
None
, "bouton radio 1"
)
bouton.connect
(
"toggled"
, self.fct_rappel, "bouton radio 1"
)
boite2.pack_start
(
bouton, True
, True
, 0
)
bouton.show
(
)
bouton =
gtk.RadioButton
(
bouton, "bouton radio 2"
)
bouton.connect
(
"toggled"
, self.fct_rappel, "bouton radio 2"
)
bouton.set_active
(
True
)
boite2.pack_start
(
bouton, True
, True
, 0
)
bouton.show
(
)
bouton =
gtk.RadioButton
(
bouton, "bouton radio 3"
)
bouton.connect
(
"toggled"
, self.fct_rappel, "bouton radio 3"
)
boite2.pack_start
(
bouton, True
, True
, 0
)
bouton.show
(
)
separateur =
gtk.HSeparator
(
)
boite1.pack_start
(
separateur, False
, True
, 0
)
separateur.show
(
)
boite2 =
gtk.VBox
(
False
, 10
)
boite2.set_border_width
(
10
)
boite1.pack_start
(
boite2, False
, True
, 0
)
boite2.show
(
)
bouton =
gtk.Button
(
"fermer"
)
bouton.connect_object
(
"clicked"
, self.quitter_pgm,
self.fenetre, None
)
boite2.pack_start
(
bouton, True
, True
, 0
)
bouton.set_flags
(
gtk.CAN_DEFAULT)
bouton.grab_default
(
)
bouton.show
(
)
self.fenetre.show
(
)
def
main
(
):
gtk.main
(
)
return
0
if
__name__
==
"__main__"
:
BoutonsRadio
(
)
main
(
)
Le code est assez explicite. Aux lignes 63-64, on fait du bouton "fermer" le widget par défaut, de sorte qu'en appuyant sur la touche "Entrée" lorsque la fenêtre est active, il émette le signal "clicked".