Vous êtes à peu près ici : Accueil  »   tutoriel PyGTK  »   PyGTK : sommaire

9.10. 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é les boutons, plus cette incrémentation/décrémentation s'accélère.

Les boites d'incrément utilisent des 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'ajustement, rappelons-nous sa fonction de création :

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

La 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 lorsque on clique sur l'un des deux boutons avec le bouton 1 de la souris
page_increment pas de l'incrémentation/décrémentation lorsque on clique sur l'un des deux boutons avec le bouton 2 de la souris
page_size inutilisé

Un clic sur un des deux boutons avec le bouton 3 de la souris peut également servir à aller directement à la valeur upper ou lower. Voyons donc comment créer une boite à incrément :

  boite_increment = gtk.SpinButton(adjustment=None, climb_rate=0.0, digits=0)

L'argument climb_rate accepte une valeur comprise entre 0.0 et 1.0 et indique le degré d'accélération de la 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 :

  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 :

  boite_increment.set_adjustment(adjustment)

  ajustement = spin_button.get_adjustment()

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

  boite_increment.set_digits(digits)

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

  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 :

  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 la méthode suivante :

  boite_increment.spin(direction, increment)

Le paramètre direction peut prendre l'une des valeurs suivantes :

  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'ajustement associé à 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'ajustement.

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' ajustement.

SPIN_END (fin) fixe la valeur de la boite d'incrément à la borne maximum de l'intervalle de l' ajustement.

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 :

  boite_increment.set_numeric(numeric)

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

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

  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' ajustement 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 :

  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 :

  boite_increment.set_update_policy(policy)

Les valeurs possibles pour policy (mode) sont :

  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'ajustement.

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' ajustement. 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 :

  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 :

Figure 9.11. Exemple de boites d'incrément

exemple d'incrément

Voici le code source de boitesincrement.py :

     1   #!/usr/bin/env python
     2   
     3   # exemple boiteincrement.py
     4   
     5   import pygtk
     6   pygtk.require('2.0')
     7   import gtk
     8   
     9   class ExempleBoiteIncrement:
    10       def modif_arrondi(self, widget, boiteincr):
    11           boiteincr.set_snap_to_ticks(widget.get_active())
    12   
    13       def modif_numerique(self, widget, boiteincr):
    14           boiteincr.set_numeric(widget.get_active())
    15   
    16       def modif_decimales(self, widget, boiteincr, boiteincr1):
    17           boiteincr1.set_digits(boiteincr.get_value_as_int())
    18   
    19       def recup_valeur(self, widget, donnees, boiteincr, boiteincr2, etiquette):
    20           if donnees == 1:
    21               tampon = "%d" % boiteincr.get_value_as_int()
    22           else:
    23               tampon = "%0.*f" % (boiteincr2.get_value_as_int(),
    24                                   boiteincr.get_value())
    25           etiquette.set_text(tampon)
    26   
    27       def __init__(self):
    28           fenetre = gtk.Window(gtk.WINDOW_TOPLEVEL)
    29           fenetre.connect("destroy", gtk.main_quit)
    30           fenetre.set_title("Boites d'increment")
    31   
    32           boite_v0 = gtk.VBox(False, 5)
    33           boite_v0.set_border_width(10)
    34           fenetre.add(boite_v0)
    35   
    36           cadre = gtk.Frame("Sans acceleration")
    37           boite_v0.pack_start(cadre, True, True, 0)
    38     
    39           boite_v1 = gtk.VBox(False, 0)
    40           boite_v1.set_border_width(5)
    41           cadre.add(boite_v1)
    42   
    43           # Boites d'increment pour le jour, le mois et l'annee
    44           boite_h = gtk.HBox(False, 0)
    45           boite_v1.pack_start(boite_h, True, True, 5)
    46     
    47           boite_v2 = gtk.VBox(False, 0)
    48           boite_h.pack_start(boite_v2, True, True, 5)
    49   
    50           etiquette = gtk.Label("Jour :")
    51           etiquette.set_alignment(0, 0.5)
    52           boite_v2.pack_start(etiquette, False, True, 0)
    53     
    54           ajustement = gtk.Adjustment(1.0, 1.0, 31.0, 1.0, 5.0, 0.0)
    55           boiteincr = gtk.SpinButton(ajustement, 0, 0)
    56           boiteincr.set_wrap(True)
    57           boite_v2.pack_start(boiteincr, False, True, 0)
    58     
    59           boite_v2 = gtk.VBox(False, 0)
    60           boite_h.pack_start(boite_v2, True, True, 5)
    61     
    62           etiquette = gtk.Label("Mois :")
    63           etiquette.set_alignment(0, 0.5)
    64           boite_v2.pack_start(etiquette, False, True, 0)
    65   
    66           ajustement = gtk.Adjustment(1.0, 1.0, 12.0, 1.0, 5.0, 0.0)
    67           boiteincr = gtk.SpinButton(ajustement, 0, 0)
    68           boiteincr.set_wrap(True)
    69           boite_v2.pack_start(boiteincr, False, True, 0)
    70     
    71           boite_v2 = gtk.VBox(False, 0)
    72           boite_h.pack_start(boite_v2, True, True, 5)
    73     
    74           etiquette = gtk.Label("Annee :")
    75           etiquette.set_alignment(0, 0.5)
    76           boite_v2.pack_start(etiquette, False, True, 0)
    77     
    78           ajustement = gtk.Adjustment(1998.0, 0.0, 2100.0, 1.0, 100.0, 0.0)
    79           boiteincr = gtk.SpinButton(ajustement, 0, 0)
    80           boiteincr.set_wrap(False)
    81           boiteincr.set_size_request(55, -1)
    82           boite_v2.pack_start(boiteincr, False, True, 0)
    83     
    84           cadre = gtk.Frame("Avec acceleration")
    85           boite_v0.pack_start(cadre, True, True, 0)
    86     
    87           boite_v1 = gtk.VBox(False, 0)
    88           boite_v1.set_border_width(5)
    89           cadre.add(boite_v1)
    90     
    91           boite_h = gtk.HBox(False, 0)
    92           boite_v1.pack_start(boite_h, False, True, 5)
    93     
    94           boite_v2 = gtk.VBox(False, 0)
    95           boite_h.pack_start(boite_v2, True, True, 5)
    96     
    97           etiquette = gtk.Label("Valeur :")
    98           etiquette.set_alignment(0, 0.5)
    99           boite_v2.pack_start(etiquette, False, True, 0)
   100     
   101           ajustement = gtk.Adjustment(0.0, -10000.0, 10000.0, 0.5, 100.0, 0.0)
   102           boiteincr1 = gtk.SpinButton(ajustement, 1.0, 2)
   103           boiteincr1.set_wrap(True)
   104           boiteincr1.set_size_request(100, -1)
   105           boite_v2.pack_start(boiteincr1, False, True, 0)
   106     
   107           boite_v2 = gtk.VBox(False, 0)
   108           boite_h.pack_start(boite_v2, True, True, 5)
   109     
   110           etiquette = gtk.Label("Decimales :")
   111           etiquette.set_alignment(0, 0.5)
   112           boite_v2.pack_start(etiquette, False, True, 0)
   113     
   114           ajustement = gtk.Adjustment(2, 1, 5, 1, 1, 0)
   115           boiteincr2 = gtk.SpinButton(ajustement, 0.0, 0)
   116           boiteincr2.set_wrap(True)
   117           ajustement.connect("value_changed", self.modif_decimales, boiteincr2, boiteincr1)
   118           boite_v2.pack_start(boiteincr2, False, True, 0)
   119     
   120           boite_h = gtk.HBox(False, 0)
   121           boite_v1.pack_start(boite_h, False, True, 5)
   122   
   123           bouton = gtk.CheckButton("Deplacement tous les 0,5")
   124           bouton.connect("clicked", self.modif_arrondi, boiteincr1)
   125           boite_v1.pack_start(bouton, True, True, 0)
   126           bouton.set_active(True)
   127     
   128           bouton = gtk.CheckButton("Saisie numerique seulement")
   129           bouton.connect("clicked", self.modif_numerique, boiteincr1)
   130           boite_v1.pack_start(bouton, True, True, 0)
   131           bouton.set_active(True)
   132     
   133           etiquette_valeur = gtk.Label("")
   134     
   135           boite_h = gtk.HBox(False, 0)
   136           boite_v1.pack_start(boite_h, False, True, 5)
   137           bouton = gtk.Button("Valeur entiere")
   138           bouton.connect("clicked", self.recup_valeur, 1, boiteincr1, boiteincr2,
   139                          etiquette_valeur)
   140           boite_h.pack_start(bouton, True, True, 5)
   141     
   142           bouton = gtk.Button("Valeur decimale")
   143           bouton.connect("clicked", self.recup_valeur, 2, boiteincr1, boiteincr2,
   144                          etiquette_valeur)
   145           boite_h.pack_start(bouton, True, True, 5)
   146     
   147           boite_v1.pack_start(etiquette_valeur, True, True, 0)
   148           etiquette_valeur.set_text("0")
   149     
   150           boite_h = gtk.HBox(False, 0)
   151           boite_v0.pack_start(boite_h, False, True, 0)
   152     
   153           bouton = gtk.Button("Fermer")
   154           bouton.connect("clicked", gtk.main_quit)
   155           boite_h.pack_start(bouton, True, True, 5)
   156           fenetre.show_all()
   157   
   158   def main():
   159       gtk.main()
   160       return 0
   161   
   162   if __name__ == "__main__":
   163       ExempleBoiteIncrement()
   164       main()