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

Apprendre à utiliser le module Python PyGTK 2.0


précédentsommairesuivant

VIII. Chapitre 8. Les widgets d'intervalle

La catégorie des widgets d'intervalle (gtk.Range) inclut l'incontournable barre de défilement ainsi que le "gradateur", un peu moins courant. Bien que l'on utilise généralement ces deux types d'objets à différentes fins, ils sont assez similaires dans leur implémentation et leur fonctionnement. Les widgets d'intervalle ont un jeu d'éléments graphiques commun : la coulisse et le curseur, qui possèdent tous les deux leur propre fenêtre X et qui reçoivent des événements. Pour faire avancer ou reculer le curseur dans la coulisse on peut le tirer avec la souris ou bien cliquer directement dans la coulisse. Dans ce second cas, et selon le bouton de la souris utilisé, le curseur viendra se positionner à l'endroit du clic ou s'en rapprochera suivant un pas prédéfini.

Comme nous venons de le voir dans le chapitre sur les ajustementsChapitre 7. Les ajustements, tous les widgets d'intervalle sont associés à un gtk.Adjustment, à partir duquel ils calculent la longueur du curseur et sa position dans la coulisse. Lorsque l'utilisateur manipule le curseur, le widget d'intervalle modifie la valeur de l'ajustement.

VIII-A. HScrollbar et VScrollbar : les barres de défilement

Voici les très classiques barres de défilement. Elles ne devraient être employées que pour faire défiler un autre widget, comme une liste, une zone de texte ou une vue orientable (il est même bien plus pratique d'utiliser une fenêtre à défilement dans la plupart des cas). Pour le reste, les gradateurs seront plus appropriés, car plus simples d'utilisation et offrant plus de fonctionnalités.

Les barres de défilement horizontale et verticale sont implémentées dans deux types différents. Il n'y a pas grand-chose à dire à leur sujet. On les crée en appelant l'une de ces méthodes :

 
Sélectionnez
1.
2.
3.
  barredefil_h = gtk.HScrollbar(adjustment=None)

  barredefil_v = gtk.VScrollbar(adjustment=None)

et voilà tout. L'argument adjustment (ajustement) attend une référence à un ajustementChapitre 7. Les ajustements existant. Si vous ne lui en fournissez pas, la méthode en créera un pour vous, ce qui peut être intéressant si vous voulez transmettre ce nouvel ajustement à la méthode constructeur d'un autre widget, qui se chargera de le configurer pour vous (une zone de texte, par exemple).

VIII-B. HScale et VScale : les gradateurs

Les gradateurs permettent à l'utilisateur de sélectionner et de manipuler une valeur dans un intervalle donné, ceci graphiquement. Ils peuvent servir, par exemple, à ajuster le degré d'agrandissement de l'aperçu d'une image, à contrôler la luminosité d'une couleur, ou encore à spécifier le nombre de minutes d'inactivité avant le lancement d'un économiseur d'écran.

VIII-B-1. Créer un gradateur

Tout comme pour les barres de défilement, il existe un type de widget pour les gradateurs verticaux et un autre pour les horizontaux (la majorité des programmeurs semble préférer ces derniers). Malgré tout, vu qu'ils fonctionnent de la même manière, nous ne les traiterons pas séparément. Les méthodes suivantes créent respectivement un gradateur vertical et un gradateur horizontal :

 
Sélectionnez
1.
2.
3.
  gradateurv = gtk.VScale(adjustment=None)

  gradateurh = gtk.HScale(adjustment=None)

L'argument adjustment (ajustement) attend une référence à un ajustementChapitre 7. Les ajustements déjà créé avec gtk.Adjustment(). Si vous ne lui en fournissez pas, la méthode en créera un anonyme dont toutes les valeurs vaudront 0.0 (ce qui n'est pas très utile ici). Afin de vous y retrouver, vous pourriez créer un ajustement dont vous fixeriez la page_size à 0.0, de sorte que sa valeur upper corresponde bien à la plus grande valeur que l'utilisateur peut sélectionner (si vous êtes déjà complètement perdu, relisez la section sur les ajustementsChapitre 7. Les ajustements pour mieux comprendre leur rôle, leur processus de création et leur manipulation).

VIII-B-2. Méthodes et signaux (enfin, au moins méthodes…)

Les gradateurs peuvent afficher un nombre représentant leur valeur courante à côté de la coulisse. Cette option, activée par défaut, peut être modifiée avec la méthode :

 
Sélectionnez
  gradateur.set_draw_value(draw_value)

Comme vous l'avez sûrement deviné, draw_value (valeur d'affichage) vaut soit TRUE soit FALSE, chacune de ces deux expressions entrainant les conséquences que l'on peut en attendre.

La valeur affichée par un gradateur est arrondie par défaut au premier chiffre après la virgule, comme la valeur de son ajustementChapitre 7. Les ajustements. Vous pouvez changer ceci avec la méthode suivante :

 
Sélectionnez
  gradateur.set_digits(digits)

digits est le nombre de décimales. Vous pouvez en demander autant que vous le souhaitez, mais sachez que seules les 13 premières seront réellement affichées.

Enfin, la valeur peut être affichée à différents endroits autour de la coulisse :

 
Sélectionnez
  gradateur.set_value_pos(pos)

L'argument pos peut prendre l'une des valeurs suivantes :

 
Sélectionnez
1.
2.
3.
4.
  POS_LEFT    # à gauche
  POS_RIGHT    # à droite
  POS_TOP    # au-dessus
  POS_BOTTOM    # au-dessous

Si vous placez la valeur le long de la coulisse (au-dessus ou au-dessous d'un gradateur horizontal, par exemple), elle suivra le curseur dans ses déplacements.

VIII-C. Méthodes communes aux widgets d'intervalle

La classe des widgets d'intervalle (gtk.Range) a des mécanismes internes assez compliqués, qui, comme tous ceux des classes "de base", ne sont pas très intéressants à moins de vouloir les bidouiller. De plus, parmi ses méthodes et signaux, la quasi-totalité n'est vraiment utile que pour écrire des widgets dérivés. On trouve cependant quelques méthodes utiles qui fonctionnent avec tous les widgets de la classe.

VIII-C-1. Définir le mode d'actualisation

Le "mode d'actualisation" d'un widget d'intervalle précise le moment où, durant sa manipulation par l'utilisateur, le widget devra changer la valeur de son ajustementChapitre 7. Les ajustements et lui faire émettre le signal "value_changed". Les différents modes d'actualisation sont :

UPDATE_CONTINUOUS(continu)

C'est le mode par défaut. Le signal "value_changed" est émis de manière continue, c'est-à-dire au moindre déplacement du curseur.

UPDATE_DISCONTINUOUS(discontinu)

Le signal "value_changed" n'est émis qu'après que le curseur a cessé de bouger et que l'utilisateur a relâché le bouton de la souris.

UPDATE_DELAYED(différé)

Le signal "value_changed" est émis lorsque l'utilisateur relâche le bouton de la souris, ou si le curseur cesse de bouger durant un court instant.

On définit le mode d'actualisation d'un widget d'intervalle en l'indiquant à l'argument policy (mode) de cette méthode :

 
Sélectionnez
  widget.set_update_policy(policy)

VIII-C-2. Définir et récupérer les ajustements

Pour définir et récupérer "à la volée" l'ajustement d'un widget d'intervalle, on utilise naturellement les méthodes :

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

  ajustement = widget.get_adjustment()

La méthode get_adjustment() renvoie une référence à l'ajustement auquel widget est connecté.

La méthode set_adjustment() ne fait absolument rien si vous lui transmettez l'ajustement que widget utilise déjà, que vous ayez modifié ou non ses valeurs. En revanche, si vous lui passez un nouvel ajustementajustementsChapitre 7. Les ajustements, elle déréférence le précédent s'il existe (voire le détruit), connecte les signaux appropriés au nouveau, puis recalcule la taille et/ou la position du curseur avant de le réafficher si nécessaire. Comme nous l'avons vu dans la section sur les ajustementsChapitre 7. Les ajustements, si vous voulez réutiliser le même, vous devriez lui faire émettre le signal "changed" quand vous modifiez directement ses valeurs :

 
Sélectionnez
  ajustement.emit("changed")

VIII-D. Clavier et souris

Tous les widgets d'intervalle de GTK réagissent aux clics de souris plus ou moins de la même manière. En cliquant dans la coulisse avec le premier bouton, on augmente ou diminue la valeur (value) de son ajustement d'un page_increment, et le curseur est déplacé en conséquence. Si l'on y clique avec le deuxième bouton, le curseur est amené directement au point cliqué. Un clic de n'importe quel bouton sur les flèches d'une barre de défilement augmente ou diminue la valeur de son ajustement d'un step_increment.

Les barres de défilement ne peuvent pas avoir le focus, elle n'ont donc aucune connexion directe avec le clavier. Chez les autres widgets d'intervalle, ces connexions (actives, bien sûr, seulement lorsque les widgets ont le focus) sont les mêmes pour les widgets horizontaux et verticaux.

Tous les widgets d'intervalle peuvent être manipulés avec les flèches haut, bas, gauche et droite du clavier, ainsi qu'avec les touches Page précédente et Page suivante. Les flèches déplacent le curseur par step_incr, et Page précédente/Page suivante par page_incr.

L'utilisateur a également la possibilité de placer le curseur directement à l'une ou l'autre des extrémités de la coulisse avec les touches Début et Fin.

VIII-E. Démonstration des widgets d'intervalle

Le programme d'exemple widgetsintervalle.py affiche une fenêtre comprenant trois widgets d'intervalle connectés au même ajustement, ainsi que plusieurs autres widgets par lesquels il est possible de modifier certains des paramètres vus plus haut ou à la section sur les ajustements. Ceci vous permettra de vous faire une idée plus précise de ce que ces paramètres contrôlent dans le widget. La figure 8.1 montre ce que l'on obtient après avoir lancé le programme :

Image non disponible
Figure 8.1. Exemple de widgets d'intervalle

Le code source de widgetsintervalle.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.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
217.
218.
219.
220.
221.
222.
223.
224.
225.
226.
227.
228.
229.
230.
231.
232.
233.
234.
235.
236.
#!/usr/bin/env python

# exemple widgetsintervalle.py

import pygtk
pygtk.require('2.0')
import gtk

# Ces fonctions sont là pour nous faciliter les choses

def nouvelle_entree(nom, rappel, donnees=None):
    entree = gtk.MenuItem(nom)
    entree.connect("activate", rappel, donnees)
    entree.show()
    return entree

def gradateurs_valeurs_defaut(gradateur):
    gradateur.set_update_policy(gtk.UPDATE_CONTINUOUS)
    gradateur.set_digits(1)
    gradateur.set_value_pos(gtk.POS_TOP)
    gradateur.set_draw_value(True)

class WidgetsIntervalle:
    def modif_position(self, entree, position):
        # Fixe la position de la valeur pour les deux gradateurs
        self.gradateurh.set_value_pos(position)
        self.gradateurv.set_value_pos(position)

    def modif_mode_actu(self, entree, mode):
        # Fixe le mode d'actualisation pour les deux gradateurs
        self.gradateurh.set_update_policy(mode)
        self.gradateurv.set_update_policy(mode)

    def modif_decimales(self, ajust):
        # Fixe le nombre de décimales pour arrondir la valeur de ajust
        self.gradateurh.set_digits(ajust.value)
        self.gradateurv.set_digits(ajust.value)

    def modif_taille_page(self, ajust2, ajust1):
        # Les valeurs "taille de la page" et "incrémentation par page" de l'ajustement 
        # exemple prennent la valeur donnée par le gradateur "Taille de la page".
        ajust1.page_size = ajust2.value
        ajust1.page_incr = ajust2.value
        # Puis on fait émettre le signal "changed" à ajust1 pour reconfigurer tous les
        # widgets qui lui sont attachés
        ajust1.emit("changed")

    def affiche_valeur(self, bouton):
        # Active ou desactive l'affichage de la valeur sur les gradateurs,
        # en fonction de l'état du bouton à bascule
        self.gradateurh.set_draw_value(bouton.get_active())
        self.gradateurv.set_draw_value(bouton.get_active())  

    # Construction de notre fenêtre exemple

    def __init__(self):
        # Creation standard d'une fenêtre
        self.fenetre = gtk.Window (gtk.WINDOW_TOPLEVEL)
        self.fenetre.connect("destroy", gtk.main_quit)
        self.fenetre.set_title("Widgets d'intervalle")

        boite1 = gtk.VBox(False, 0)
        self.fenetre.add(boite1)
        boite1.show()

        boite2 = gtk.HBox(False, 10)
        boite2.set_border_width(10)
        boite1.pack_start(boite2, True, True, 0)
        boite2.show()

        # valeur, minimale, maximale, incr/pas, incr/page, taille de la page
        # Notez que le paramètre "taille de la page" n'a d'effet qu'avec les
        # barres de défilement, la plus haute valeur étant alors égale à
        # "maximale" moins "taille de la page"
        ajust1 = gtk.Adjustment(0.0, 0.0, 101.0, 0.1, 1.0, 1.0)
  
        self.gradateurv = gtk.VScale(ajust1)
        gradateurs_valeurs_defaut(self.gradateurv)
        boite2.pack_start(self.gradateurv, True, True, 0)
        self.gradateurv.show()

        boite3 = gtk.VBox(False, 10)
        boite2.pack_start(boite3, True, True, 0)
        boite3.show()

        # On réutilise le même ajustement
        self.gradateurh = gtk.HScale(ajust1)
        self.gradateurh.set_size_request(200, 30)
        gradateurs_valeurs_defaut(self.gradateurh)
        boite3.pack_start(self.gradateurh, True, True, 0)
        self.gradateurh.show()

        # On réutilise encore le même ajustement
        barredefil = gtk.HScrollbar(ajust1)
        # Notez que l'on demande a ce que les gradateurs soient toujours
        # actualisés en continu quand la barre de défilement est manipulée
        barredefil.set_update_policy(gtk.UPDATE_CONTINUOUS)
        boite3.pack_start(barredefil, True, True, 0)
        barredefil.show()

        boite2 = gtk.HBox(False, 10)
        boite2.set_border_width(10)
        boite1.pack_start(boite2, True, True, 0)
        boite2.show()

        # Un bouton à bascule pour afficher ou pas la valeur
        bouton = gtk.CheckButton("Afficher la valeur sur les gradateurs")
        bouton.set_active(True)
        bouton.connect("toggled", self.affiche_valeur)
        boite2.pack_start(bouton, True, True, 0)
        bouton.show()
  
        boite2 = gtk.HBox(False, 10)
        boite2.set_border_width(10)

        # Un menu déroulant pour changer la position de la valeur
        etiquette = gtk.Label("Position de la valeur :")
        boite2.pack_start(etiquette, False, False, 0)
        etiquette.show()
  
        menuderoul = gtk.OptionMenu()
        menu = gtk.Menu()

        entree = nouvelle_entree ("Au-dessus", self.modif_position, gtk.POS_TOP)
        menu.append(entree)
  
        entree = nouvelle_entree ("Au-dessous", self.modif_position,
                                  gtk.POS_BOTTOM)
        menu.append(entree)
  
        entree = nouvelle_entree ("A gauche", self.modif_position, gtk.POS_LEFT)
        menu.append(entree)
  
        entree = nouvelle_entree ("A droite", self.modif_position, gtk.POS_RIGHT)
        menu.append(entree)
  
        menuderoul.set_menu(menu)
        boite2.pack_start(menuderoul, True, True, 0)
        menuderoul.show()

        boite1.pack_start(boite2, True, True, 0)
        boite2.show()

        boite2 = gtk.HBox(False, 10)
        boite2.set_border_width(10)

        # Encore un autre menu déroulant, cette fois-ci pour le mode
        # d'actualisation des gradateurs
        etiquette = gtk.Label("Mode d'actualisation :")
        boite2.pack_start(etiquette, False, False, 0)
        etiquette.show()
  
        menuderoul = gtk.OptionMenu()
        menu = gtk.Menu()
  
        entree = nouvelle_entree("Continu", self.modif_mode_actu,
                                 gtk.UPDATE_CONTINUOUS)
        menu.append(entree)
  
        entree = nouvelle_entree ("Discontinu", self.modif_mode_actu,
                                  gtk.UPDATE_DISCONTINUOUS)
        menu.append(entree)
  
        entree = nouvelle_entree ("Differe", self.modif_mode_actu,
                                  gtk.UPDATE_DELAYED)
        menu.append(entree)
  
        menuderoul.set_menu(menu)
        boite2.pack_start(menuderoul, True, True, 0)
        menuderoul.show()
  
        boite1.pack_start(boite2, True, True, 0)
        boite2.show()

        boite2 = gtk.HBox(False, 10)
        boite2.set_border_width(10)
  
        # Création d'un gradateur horizontal pour choisir le nombre de
        # décimales dans les gradateurs exemples.
        etiquette = gtk.Label("Decimales :")
        boite2.pack_start(etiquette, False, False, 0)
        etiquette.show()

        ajust2 = gtk.Adjustment(1.0, 0.0, 5.0, 1.0, 1.0, 0.0)
        ajust2.connect("value_changed", self.modif_decimales)
        gradateur = gtk.HScale(ajust2)
        gradateur.set_digits(0)
        boite2.pack_start(gradateur, True, True, 0)
        gradateur.show()

        boite1.pack_start(boite2, True, True, 0)
        boite2.show()
  
        boite2 = gtk.HBox(False, 10)
        boite2.set_border_width(10)
  
        # Un dernier gradateur horizontal pour choisir la taille de la page
        # de la barre de défilement.
        etiquette = gtk.Label("Taille de la page de la\nbarre de defilement :")
        boite2.pack_start(etiquette, False, False, 0)
        etiquette.show()

        ajust2 = gtk.Adjustment(1.0, 1.0, 101.0, 1.0, 1.0, 0.0)
        ajust2.connect("value_changed", self.modif_taille_page, ajust1)
        gradateur = gtk.HScale(ajust2)
        gradateur.set_digits(0)
        boite2.pack_start(gradateur, True, True, 0)
        gradateur.show()

        boite1.pack_start(boite2, True, True, 0)
        boite2.show()

        separateur = gtk.HSeparator()
        boite1.pack_start(separateur, False, True, 0)
        separateur.show()

        boite2 = gtk.VBox(False, 10)
        boite2.set_border_width(10)
        boite1.pack_start(boite2, False, True, 0)
        boite2.show()

        bouton = gtk.Button("Quitter")
        bouton.connect_object("clicked", gtk.main_quit, self.fenetre)
        boite2.pack_start(bouton, True, True, 0)
        bouton.set_flags(gtk.CAN_DEFAULT)
        bouton.grab_default()
        bouton.show()
        self.fenetre.show()

def main():
    gtk.main()
    return 0            

if __name__ == "__main__":
    WidgetsIntervalle()
    main()

Vous avez peut-être remarqué que le programme n'appelle pas la méthode connect() pour l'événement "delete_event", mais seulement pour le signal "destroy", et pourtant tout se passe très bien. Ceci est dû au fait qu'un événement "delete_event" non traité, déclenche automatiquement l'émission du signal "destroy" sur la fenêtre.


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.