IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Apprendre à utiliser le module Python PyGTK 2.0


précédentsommairesuivant

IX. Chapitre 9. Widgets divers

IX-A. 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 àLa boîte à évènement (EventBox)événements ou dans des boutons (voir Boutons simplesLes boutons simples).

Pour créer une étiquette, on utilise la méthode suivante :

 
Sélectionnez
  etiquette = gtk.Label(str)

L'unique argument à fournir, str, est la chaine de caractères que doit afficher l'étiquette. Pour changer ce texte une fois l'étiquette créée, on fera appel à la méthode :

 
Sélectionnez
  etiquette.set_text(str)

etiquette est l'étiquette précédemment créée, et str la nouvelle chaine de caractères. L'espace alloué à la nouvelle chaine sera automatiquement ajusté si nécessaire. Vous pouvez créer une étiquette de plusieurs lignes en insérant des sauts de lignes dans la chaine de caractères.

Pour récupérer la chaine courante, faites :

 
Sélectionnez
  chaine = etiquette.get_text()

etiquette est l'étiquette que vous avez créée, et chaine la chaine de caractères. On peut définir le type d'alignement du texte d'une étiquette avec :

 
Sélectionnez
  etiquette.set_justify(jtype)

L'argument jtype peut prendre les valeurs suivantes :

 
Sélectionnez
1.
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 :

 
Sélectionnez
  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 :

 
Sélectionnez
  etiquette.set_pattern(pattern)

L'argument pattern (patron) précise le profil du soulignement. Il s'agit d'une chaine 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 chaine "__ __" 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 :

Image non disponible
Figure 9.1. Exemples d'étiquettes

Le code source du programme est le suivant :

 
Sélectionnez
1.
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.\nDeuxieme 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.\nTroisieme 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\ndont 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.

IX-B. 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 :

 
Sélectionnez
1.
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 :

 
Sélectionnez
1.
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 :

 
Sélectionnez
1.
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 :

Image non disponible
Figure 9.2. Exemple de boutons avec flèches

Voici le code source de fleches.py :

 
Sélectionnez
1.
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 boite 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()

IX-C. Les infobulles

Les infobulles sont les petites chaines 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.

 
Sélectionnez
  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 :

 
Sélectionnez
  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 apparaitre et le second (tip_text) le texte qu'elle doit afficher. Le dernier argument (tip_private) est une chaine 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 :

Image non disponible
Figure 9.3. Exemple d'infobulle

Voici le code source de infobulles.py :

 
Sélectionnez
1.
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 fenêtre
        fenetre.set_border_width(10)

        # On crée une boite 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 :

 
Sélectionnez
  infobulles.enable()

Active un groupe d'infobulles désactivé.

 
Sélectionnez
  infobulles.disable()

Désactive un groupe d'infobulles activé.

 
Sélectionnez
  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 :-).

IX-D. 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 :

 
Sélectionnez
  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.

 
Sélectionnez
  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 :

 
Sélectionnez
  barreprogression.set_orientation(orientation)

L'argument orientation peut prendre les valeurs suivantes, qui indiquent le sens de progression de la barre :

 
Sélectionnez
1.
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.

 
Sélectionnez
  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.

 
Sélectionnez
  barreprogression.set_pulse_step(fraction)

Lorsqu'elle n'est pas en mode "activité", la barre de progression peut également afficher une chaine de texte configurable dans sa coulisse. On utilise alors la méthode suivante :

 
Sélectionnez
  barreprogression.set_text(text)

Notez que set_text() ne prend pas en charge le formatage de type printf() des barres de progression de GTK+ 1.2.

Pour désactiver l'affichage de la chaine 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 :

 
Sélectionnez
  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 :

Image non disponible
Figure 9.4. Exemple de barre de progression

Voici le code source de barreprogression.py :

 
Sélectionnez
1.
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()

IX-E. Les boites de dialogue

Les boites 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 boite horizontale contenant un séparateur, et place à sa suite une boite horizontale qui sera la "zone d'action" (action area).

Les boites 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 :

 
Sélectionnez
  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 boite de dialogue :

 
Sélectionnez
1.
2.
3.
  DIALOG_MODAL            # rend la boite de dialogue modale
  DIALOG_DESTROY_WITH_PARENT    # détruit la boite de dialogue quand son parent est détruit
  DIALOG_NO_SEPARATOR        # pas de séparateur entre la boite 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 mot-clés.

Vous savez maintenant créer une boite de dialogue. Il ne vous reste plus qu'à vous en servir. Vous pourriez placer un bouton dans la zone d'action :

 
Sélectionnez
1.
2.
3.
  bouton = ...
  boitedialogue.action_area.pack_start(bouton, True, True, 0)
  bouton.show()

Vous pourriez également enrichir votre boite verticale d'une étiquette, par exemple. Essayer quelque chose dans ce style :

 
Sélectionnez
1.
2.
3.
  etiquette = gtk.Label("Cool, la boite de dialogue")
  boitedialogue.vbox.pack_start(etiquette, True, True, 0)
  etiquette.show()

En guise d'exemple d'utilisation de la boite 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 boite 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 (boites 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 boites. Il est tout à fait possible, par exemple, de placer un tableau dans la boite verticale.

IX-F. 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 :

 
Sélectionnez
  image = gtk.Image()

Puis on y charge l'image en utilisant l'une des méthodes suivantes :

 
Sélectionnez
1.
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 :

 
Sélectionnez
1.
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        #          "        : boite 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 :

Image non disponible
Figure 9.5. Images exemples dans des boutons

Voici le code source :

 
Sélectionnez
1.
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
        fenêtre = gtk.Window(gtk.WINDOW_TOPLEVEL)
        fenetre.connect("delete_event", self.fermer_application)
        fenetre.set_border_width(10)
        fenetre.show()

        # Une boite 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()

IX-F-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.

 
Sélectionnez
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 :

 
Sélectionnez
  pixmap, masque = gtk.gdk.pixmap_create_from_xpm(window, transparent_color, filename)

Le format XPM est une 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 :

 
Sélectionnez
  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 :

 
Sélectionnez
1.
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 :

 
Sélectionnez
  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 :

Image non disponible
Figure 9.6. Exemples de pixmap dans un bouton

Voici le code source :

 
Sélectionnez
1.
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
        fenêtre = gtk.Window(gtk.WINDOW_TOPLEVEL)
        fenetre.connect("delete_event", self.fermer_application)
        fenetre.set_border_width(10)
        fenetre.show()

        # venons-en à la création 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 :

Image non disponible
Figure 9.7. Exemple de fenêtre en forme de brouette

Voici le code source de brouette.py :

 
Sélectionnez
1.
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$%svbzz,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.
        fenêtre = 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 à 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.

IX-G. 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 :

 
Sélectionnez
1.
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 :

 
Sélectionnez
  regle.set_metric(metric)

L'unité de mesure par défaut est PIXELS.

 
Sélectionnez
  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 :

 
Sélectionnez
  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 :

 
Sélectionnez
  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 :

 
Sélectionnez
  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 :

 
Sélectionnez
1.
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 :

Image non disponible
Figure 9.8. Exemple de règles

Le code source de regles.py est le suivant :

 
Sélectionnez
1.
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):
        fenêtre = 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.

IX-H. 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 à :

 
Sélectionnez
  barredetat = gtk.Statusbar()

On obtient un nouvel identifiant contextuel en invoquant la méthode suivante avec une courte description textuelle du contexte (context_description) :

 
Sélectionnez
  context_id = barredetat.get_context_id(context_description)

Trois autres méthodes agissent sur les barres d'état :

 
Sélectionnez
1.
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 :

Image non disponible
Figure 9.9. Exemple de barre d'état

Voici le code source de barredetat.py :

 
Sélectionnez
1.
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
        fenêtre = 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()

IX-I. Les champs de saisie

Le widget gtk.Entry permet la saisie et l'affichage de texte dans une boite, 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 boite, soit y ajouter du texte avant ou après.

La fonction de création d'un champ de saisie est la suivante :

 
Sélectionnez
  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 :

 
Sélectionnez
  champsaisie.set_max_length(max)

La méthode qui suit modifie le texte présent dans le gtk.Entry.

 
Sélectionnez
  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 :

 
Sélectionnez
  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.

 
Sélectionnez
  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é.

 
Sélectionnez
  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) :

 
Sélectionnez
  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.

 
Sélectionnez
  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 :

Image non disponible
Figure 9.10. Exemple de champ de saisie

Voici le code source de champsaisie.py :

 
Sélectionnez
1.
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 du 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
        fenêtre = 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, fenêtre)
        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()

IX-J. Les boites d'incrément

On utilise généralement les boites 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és les boutons, plus cette incrémentation/décrémentation s'accélère.

Les boites 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 :

 
Sélectionnez
  ajustement = gtk.Adjustment(value=0, lower=0, upper=0, step_incr=0, page_incr=0, page_size=0)

La boite d'incrément utilise ces attributs de l'ajustement de la manière suivante :

value

valeur initiale de la boite 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 lorsqu’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 lorsqu’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 boite à incrément :

 
Sélectionnez
  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 boite d'incrément. L'argument digits spécifie le nombre de décimales de la valeur affichée.

On peut reconfigurer une boite à incrément après sa création en appelant la méthode suivante :

 
Sélectionnez
  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 :

 
Sélectionnez
1.
2.
3.
  boite_increment.set_adjustment(adjustment)

  ajustement = spin_button.get_adjustment()

On peut également modifier le nombre de décimales ainsi :

 
Sélectionnez
  boite_increment.set_digits(digits)

La valeur affichée par une boite d'incrément peut être changée avec cette méthode :

 
Sélectionnez
  boite_increment.set_value(value)

La valeur courante d'une boite d'incrément peut être récupérée sous sa forme décimale ou entière à l'aide des deux méthodes suivantes :

 
Sélectionnez
1.
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 :

 
Sélectionnez
  boite_increment.spin(direction, increment)

Le paramètre direction peut prendre l'une de ces valeurs :

 
Sélectionnez
1.
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 boite 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 boite 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 boite d'incrément en lui ajoutant/soustrayant celle de increment.

SPIN_HOME (début) fixe la valeur de la boite d'incrément à la borne minimum de l'intervalle de l'ajustementChapitre 7. Les ajustements.

SPIN_END (fin) fixe la valeur de la boite 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 boite 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 boite de texte du gtk.SpinButton ne puisse contenir que des valeurs numériques. L'utilisateur ne pourra alors pas y saisir autre chose :

 
Sélectionnez
  boite_increment.set_numeric(numeric)

Si numeric vaut TRUE (vrai), le champ de saisie n'acceptera que les valeurs numériques. Si elle vaut FALSE (faux), aucune contrainte n'est posée.

On peut indiquer si l'on veut que la boite 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 :

 
Sélectionnez
  boite_increment.set_wrap(wrap)

La boite d'incrément tournera en boucle si wrap vaut TRUE.

On peut faire en sorte que la boite 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 boite d'incrément). On fera alors appel à la méthode suivante, où snap_to_ticks (s'accrocher aux marques) devra valoir TRUE :

 
Sélectionnez
  boite_increment.set_snap_to_ticks(snap_to_ticks)

Le mode d'actualisation d'une boite d'incrément peut être modifié avec la méthode suivante :

 
Sélectionnez
  boite_increment.set_update_policy(policy)

Les valeurs possibles pour policy (mode) sont :

 
Sélectionnez
1.
2.
3.
  UPDATE_ALWAYS

  UPDATE_IF_VALID

Ces modes d'actualisation affectent le comportement de la boite 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 boite 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 boite d'incrément :

 
Sélectionnez
  boite_increment.update()

Le programme d'exemple boitesincrement.py offre une démonstration d'utilisation des boites 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 :

Image non disponible
Figure 9.11. Exemple de boites d'incrément

Voici le code source de boitesincrement.py :

 
Sélectionnez
1.
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):
        fenêtre = gtk.Window(gtk.WINDOW_TOPLEVEL)
        fenetre.connect("destroy", gtk.main_quit)
        fenetre.set_title("Boites 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)

        # Boites 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()

IX-K. 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 :

 
Sélectionnez
1.
2.
3.
  listder.entry

  listeder.list

Pour commencer, on créera une liste déroulante ainsi :

 
Sélectionnez
  listeder = gtk.Combo()

Maintenant, si l'on souhaite définir la chaine de caractères du champ de saisie, la manipulation doit se faire directement sur ce dernier :

 
Sélectionnez
  listeder.entry.set_text(text)

Pour définir les valeurs de la liste, on utilise la méthode suivante :

 
Sélectionnez
  listeder.set_popdown_strings(strings)

Mais avant, il faudra créer une liste regroupant les chaines de caractères que l'on veut.

Voici un segment de code typique pour créer un ensemble d'options :

 
Sélectionnez
1.
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 :

 
Sélectionnez
1.
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 apparaitre 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 :

 
Sélectionnez
  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 :

 
Sélectionnez
  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 :

 
Sélectionnez
  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.

IX-L. 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 :

 
Sélectionnez
  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.

 
Sélectionnez
1.
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 :

 
Sélectionnez
  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 apparaitre 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 lorsqu’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 :

 
Sélectionnez
1.
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 :

 
Sélectionnez
1.
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.

 
Sélectionnez
  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 :

 
Sélectionnez
1.
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électionné 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 :

Image non disponible
Figure 9.12. Exemple de calendrier

Voici le code source de calendrier.py :

 
Sélectionnez
1.
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<

IX-M. 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.

 
Sélectionnez
  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.

 
Sélectionnez
  dialselectcouleur = gtk.ColorSelectionDialog(title)

title (titre) est une chaine de caractères à utiliser pour la barre de titre de la boite 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 boite 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 :

 
Sélectionnez
  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.

 
Sélectionnez
  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é.

 
Sélectionnez
  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).

 
Sélectionnez
  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 boite de dialogue de sélection de couleur. Les modifications de couleur effectuées dans cette boite de dialogue entrainent le changement de la couleur d'arrière-plan de la zone de dessin. La Figure 9.13 montre ce programme en exécution :

Image non disponible
Figure 9.13. Exemple de sélecteur de couleur

Le code source de selectcouleur.py est le suivant :

 
Sélectionnez
1.
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 boite 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 boite 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
        fenêtre = 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()

IX-N. Le sélecteur de fichier

Le sélecteur de fichier est un moyen simple et rapide d'afficher une boite 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 boite de sélection de fichier, on utilise :

 
Sélectionnez
  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 :

 
Sélectionnez
  selectfichier.set_filename(filename)

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 :

 
Sélectionnez
  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 :

 
Sélectionnez
1.
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                # (boite 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 : boite 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 :

Image non disponible
Figure 9.14. Exemple de sélecteur de fichier

Le code source de selectfichier.py est le suivant :

 
Sélectionnez
1.
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 boite 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()

IX-O. 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 boite 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 boite de dialogue du sélecteur de police :

Image non disponible
Figure 9.15. Boite de dialogue du sélecteur de police

La boite 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 boite de dialogue est la suivante :

 
Sélectionnez
  dialselectpolice = gtk.FontSelectionDialog(title)

Le titre (title) est une chaine de caractères qui sera utilisée comme texte pour la barre de titre.

Une instance de gtk.FontSelectionDialog possède plusieurs attributs :

 
Sélectionnez
1.
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 boite 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 :

 
Sélectionnez
  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 :

 
Sélectionnez
  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 :

 
Sélectionnez
  nom_police = dialselectpolice.get_font_name()

La boite 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 :

 
Sélectionnez
  dialselectpolice.set_preview_text(text)

Le texte de l'aperçu peut être récupéré à l'aide de la méthode suivante :

 
Sélectionnez
  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 boite de dialogue.


précédentsommairesuivant

Copyright © 2005 John Finlay. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.