La sélection de valeurs numériques
1. Présentation
Nous allons dans ce chapitre étudier trois widgets différents qui vont nous permettre de définir une valeur numérique sans avoir à la saisir au clavier. Le premier widget que nous allons étudier est
GtkScrollbar qui se dérive en deux widgets différents, un qui est vertical et l'autre horizontal. Puis nous étudierons le widget
GtkScale qui lui aussi se décline en un widget vertical et un horizontal. Et nous terminerons avec le widget
GtkSpinButton.
1.1 Hiérarchie
GObject ->
GtkObject ->
GtkWidget ->
GtkEntry ->
GtkSpinButton
GObject ->
GtkObject ->
GtkWidget ->
GtkRange ->
GtkScale ->
GtkHScale
GObject ->
GtkObject ->
GtkWidget ->
GtkRange ->
GtkScale ->
GtkVScale
GObject ->
GtkObject ->
GtkWidget ->
GtkRange ->
GtkScrollbar ->
GtkHScrollbar
GObject ->
GtkObject ->
GtkWidget ->
GtkRange ->
GtkScrollbar ->
GtkVScrollbar
2. Pré requis
Ces trois widgets permettent de choisir une valeur numérique à l'intérieur d'une fourchette de valeurs bien définies. Le fonctionnement similaire de ces trois widgets est rendu possible par l'utilisation de l'objet
GtkAdjustment?. Nous allons donc tout d'abord acquérir les notions nécessaires sur ce widget pour comprendre les widgets de sélection.
2.1 Structure de l'objet GtkAdjustment?.
struct _GtkAdjustment
{
GtkObject parent_instance;
gdouble lower;
gdouble upper;
gdouble value;
gdouble step_increment;
gdouble page_increment;
gdouble page_size;
}
La propriété
parent_instance nous dit tout simplement que l'objet
GtkAdjustment? dérive directement de
GtkObject. Les valeurs
lower et
upper déterminent respectivement la valeur minimale et la valeur maximale que peut prendre le widget qui utilise cet objet. La valeur
value donne la valeur actuelle telle qu'elle est définie par le widget. Les valeurs
step_increment et
page_increment définissent de combien value sera modifiée à chaque fois que l'utilisateur demande d'augmenter ou de diminuer la valeur. Nous verrons la différence entre ces deux valeurs avec l'étude des widgets
GtkScrollbar et
GtkScale. La dernière propriété
page_size définit la taille d'une page, mais là aussi cela deviendra plus clair avec l'étude des widgets qui va suivre.
2.2 Les fonctions de bases
La première classe de base est :
ajustement = gtk.Adjustment(value, lower, upper, step_increment, page_increment, page_size)
Nous retrouvons ici tous les paramètres définis précédemment.
Ensuite pour modifier ou récupérer la valeur actuelle de l'objet, il y a ces deux méthodes :
ajustement.set_value(value)
valeur = ajustement.get_value()
Bien entendu la première méthode change le widget utilisateur pour que sa position représente la valeur value, et la deuxième méthode récupère cette valeur.
Et pour terminer voici la méthode qui permet de modifier les valeurs limites de l'objet :
ajustement.clamp_page(lower, upper)
Nous avons vu l'essentiel des méthodes de l'objet
GtkAdjustment?, mais en règle générale, il n'est pas nécessaire de les utiliser, car les widgets qui nécessitent cet objet, ont leurs propres méthodes d'accès et de modification des paramètres.
Comme nous l'avons dit dans la présentation, ce widget se décline en deux variantes différentes :
Mais nous allons voir que mise à part les classes de création, toutes les autres modifications se font avec les mêmes méthodes quel que soit le widget utilisé.
3.1 Création
Voici donc les deux classes de création disponibles :
vscrollbar = gtk.VScrollbar()
hscrollbar = gtk.HScrollbar()
La première crée donc une
GtkVScrollbar et la seconde une
GtkHScrollbar. De plus, nous voyons qu'il faut obligatoirement un
GtkAdjustment? pour définir les paramètres du widget. Il va donc falloir dans un premier temps créer un
GtkAdjustment? et définir ses valeurs.
Pour ce qui est des valeurs
lower,
upper, et
value, il n'y a pas de problème. Par contre pour les valeurs
step_increment et
page_increment, il faut connaître un peu le fonctionnement de ce widget. Regardons d'abord à quoi ressemble un widget
GtkHScrollbar.
La zone 1 est en fait l'afficheur de la valeur actuelle prise par la
GtkScrollbar. Elle permet aussi de sélectionner une valeur en le déplaçant à l'aide de la souris. Les deux zones 2 permettent de modifier la valeur de la zone 1. Un clic de souris sur une de ces zones modifiera la valeur de plus ou moins la valeur de
step_increment. Les zones 3 ont le même objectif que les zones 2 mais cette fois avec une modification de valeur de
page_increment.
Il reste encore le dernier paramètre à configurer. Ce dernier,
page_size, détermine la taille de la zone 1. Si, par exemple le widget
GtkScrollbar a une valeur minimale de 0 et une valeur maximale de 100, et nous définissons
page_size comme ayant une valeur de 50, la zone 1 du widget aura une longueur égale à la moitié de celle du widget. Le dernier point sur ce paramètre est qu'il détermine aussi la valeur qu'il faut donner à
upper. Ce widget fonctionnant en utilisant des pages, la valeur
upper n'est jamais atteinte. Si l'on veut pouvoir choisir une valeur entre 0 et 100 avec un page_size égale à 50, il faudra mettre upper à 150 soit le
upper théorique plus
page_size.
En effet, ce widget n'a pas comme vocation première de permettre de sélectionner des valeurs numériques mais plutôt l'affichage d'autre widget dont la hauteur (ou la largeur) est supérieure à la zone d'affichage. Ainsi lorsque la barre de sélection est complètement à gauche, la valeur de la
GtkScrollbar est bien de 0, mais elle considère qu'elle affiche une zone allant de 0 à
page_size (50 dans notre exemple). De ce fait, si la barre de sélection est complètement à droite la valeur de la
GtkScrollbar sera égale à upper-page_size et considèrera qu'elle affiche une zone allant de upper-page_size à upper (50 à 100 dans notre exemple). Pour conclure, il faut toujours donner à
upper la valeur maximale que nous souhaitons pouvoir sélectionner plus la valeur de page_size.
Nous savons maintenant comment configurer le
GtkAdjustment? afin de créer proprement une
GtkScrollbar.
3.2 La gestion des valeurs
Nous allons maintenant traiter les méthodes de gestion d'une
GtkScrollbar. Pour cela, nous n'allons pas utiliser les widgets
GtkHScrollbar et
GtkVScrollbar car il n'y a pour chaque widget qu'une seule fonction de création, ni le widget
GtkScrollbar car il ne possède aucune méthode, mais le widget
GtkRange dont dérive toute cette panoplie.
Tout d'abord pour fixer la valeur d'une
GtkScrollbar, nous avons à notre disposition la méthode suivante :
scrollbar.range_set_value(value)
Bien sûr le premier paramètre est la valeur que nous voulons donner à notre
GtkScrollbar.
A l'inverse, la méthode nous permettant de connaître la valeur de la
GtkScrollbar est :
valeur = scrollbar.get_value(range)
Ensuite le widget
GtkRange nous offre la possibilité de modifier les bornes du widget ainsi que les différents pas avec ces deux méthodes :
scrollbar.set_increments(step, page)
scrollbar.set_range(min, max)
La première méthode modifie les pas de modification. Les paramètres
step et
page correspondent aux paramètres
step_increment et
page_increment du
GtkAdjustment? associé au widget.
La deuxième méthode permet de modifier les valeurs minimale et maximale que le widget peut prendre. Là encore, il faut penser au problème de la valeur maximale pour bien configurer max.
Une autre possibilité pour modifier ces paramètres est de créer un nouveau
GtkAdjustment? et de l'associer à la
GtkScrollbar avec cette fonction :
scrollbar.set_adjustment(adjustment)
3.3 Programme exemple
Notre premier exemple de ce chapitre va nous permettre de sélection les valeurs RGB que nous souhaitons affecter. La couleur formée par ces valeurs ne sera pas affichée car nous nous contenterons d'afficher ces valeurs dans un label.
Pour modifier les valeurs des labels en fonction des modifications des
GtkScrollbar, nous allons capturer le signal "value-changed" de chaque
GtkScrollbar.
# -*- Encoding:Latin-1 -*-
import gtk
def main():
window = gtk.Window(gtk.WINDOW_TOPLEVEL)
window.set_title("GtkScrollbar")
window.set_default_size(320, 200)
window.set_border_width(4)
main_vbox = gtk.VBox(True, 0)
window.add(main_vbox)
frame = gtk.Frame("Rouge")
main_vbox.pack_start(frame, False, False, 0)
color_box = gtk.VBox(True, 0)
frame.add(color_box)
# Label d'affichage de valeur R
label = gtk.Label("0")
color_box.pack_start(label, False, False, 0)
# Creation d un GtkAdjustment
adjust = gtk.Adjustment(0, 0, 256, 1, 10, 1)
# Creation d une scrollbar horizontale
scrollbar = gtk.HScrollbar(adjust)
color_box.pack_start(scrollbar, True, True, 0)
# Connexion du signal pour modification de l affichage
scrollbar.connect("value-changed", OnScrollbarChange, label)
# Idem pour G
frame = gtk.Frame("Vert")
main_vbox.pack_start(frame, False, False, 0)
color_box = gtk.VBox(True, 0)
frame.add(color_box)
label = gtk.Label("0")
color_box.pack_start(label, False, False, 0)
adjust = gtk.Adjustment(0, 0, 256, 1, 10, 1)
scrollbar = gtk.HScrollbar(adjust)
color_box.pack_start(scrollbar, True, True, 0)
scrollbar.connect("value-changed", OnScrollbarChange, label)
# Idem pour B
frame = gtk.Frame("Bleu")
main_vbox.pack_start(frame, False, False, 0)
color_box = gtk.VBox(True, 0)
frame.add(color_box)
label = gtk.Label("0")
color_box.pack_start(label, False, False, 0)
adjust = gtk.Adjustment(0, 0, 256, 1, 10, 1)
scrollbar = gtk.HScrollbar(adjust)
color_box.pack_start(scrollbar, True, True, 0)
scrollbar.connect("value-changed", OnScrollbarChange, pLabel)
window.show_all()
window.connect("destroy", gtk.main_quit, None)
gtk.main()
def OnScrollbarChange(widget, data):
# Recuperation de la valeur de la scrollbar
value = widget.get_value()
# Creation du nouveau label
label = "%d" % value
# Modification du label
data.set_text(label)
if __name__ == '__main__':
main()
Résultat

Les widgets
GtkHScale et
GtkVScale ont un fonctionnement quasi identique aux widget
GtkHScrollbar et
GtkVScrollbar mais sont plus simple d'utilisation. Un des avantages de ce widget est qu'il offre la possibilité d'afficher tout seul sa valeur.
4.1 Création
Comme pour les
GtkScrollbar, nous pouvons créer des
GtkScale à l'aide de
GtkAdjustment? avec ces fonctions :
GtkWidget* gtk_vscale_new(GtkAdjustment? *adjustment);
GtkWidget* gtk_hscale_new (GtkAdjustment? *adjustment);
La première fonction crée donc un
GtkScale vertical alors la deuxième un
GtkScale horizontal.
Mais pour ne pas avoir à créer un objet
GtkAdjustment?, les créateurs de GTK+ ont pensé à nous fournir une fonction qui n'en a pas besoin :
GtkWidget* gtk_vscale_new_with_range (gdouble min, gdouble max, gdouble step);
GtkWidget* gtk_hscale_new_with_range (gdouble min, gdouble max, gdouble step);
Avec ces quatre fonctions, la signification de
step (ou
step_increment si l'on utilise un
GtkAdjustment?) est un peu différente car le widget
GtkScale n'a pas de bouton fléché comme
GtkScrollbar. Cette valeur est utilisée pour un déplacement à l'aide des touches fléchées lorsque le widget a le focus. De plus, si nous n'utilisons pas de
GtkAdjustment?, la valeur de
page_increment est égale à dix fois celle de
step.
4.2 La gestion des valeurs.
Pour récupérer ou fixer les différentes valeurs d'un widget
GtkScale il faut, comme pour le widget
GtkScrollbar, utiliser les fonctions du widget
GtkRange qui ont été décrites plus haut. Nous n'allons donc pas revenir dessus.
4.3 Affichage de la valeur sous forme de label.
Comme nous l'avons dit dans la présentation de ce widget, il s'occupe seul d'afficher et de mettre à jour un label qui affiche la valeur du widget. Par défaut, le label est affiché au-dessus du
GtkScale. Etudions les quelques fonctions qui nous sont fournis pour gérer cet affichage.
void gtk_scale_set_draw_value (GtkScale *scale, gboolean draw_value);
gboolean gtk_scale_get_draw_value (GtkScale *scale);
La première fonction nous permet de décider si nous voulons qu'un label s'affiche ou pas. Pour cela il suffit de mettre le paramètre
draw_value à TRUE si nous souhaitons qu'il s'affiche ou FALSE si nous ne le souhaitons pas. En ce qui concerne le premier paramètre, il faut utiliser la macro de conversion GTK_SCALE().
La deuxième fonction permet de savoir si le label est affiché ou pas.
Ensuite nous avons la possibilité de gérer le nombre de chiffre après la virgule qui sont affichés :
void gtk_scale_set_digits (GtkScale *scale, gint digits);
gint gtk_scale_get_digits (GtkScale *scale);
Dans la première fonction,
digit est bien sûr le nombre de chiffre après la virgule à afficher.
Et pour terminer, nous allons voir comment gérer la position du label par rapport à la barre de sélection :
void gtk_scale_set_value_pos (GtkScale *scale, GtkPositionType? pos);
GtkPositionType? gtk_scale_get_value_pos (GtkScale *scale);
Le paramètre
pos (de la première fonction) peut prendre une de ces quatre valeurs :
- GTK_POS_LEFT pour le mettre à gauche ;
- GTK_POS_RIGHT pour le mettre à droite ;
- GTK_POS_TOP pour le mettre au-dessus ;
- GTK_POS_BOTTOM pour le mettre en dessous.
4.4 Exemple.
Nous allons reprendre l'exemple précédent que nous allons transformer pour l'utilisation de widget
GtkHScale ce qui le rendra plus simple. Cependant, pour utiliser les fonctions du widget
GtkScale, le premier
GtkHScale aura un label au dessus, le second aura un label en dessous et le troisième pas du tout.
#include <stdlib.h>
#include <gtk/gtk.h>
int main(int argc,char **argv)
{
GtkWidget* pWindow;
GtkWidget *pMainVBox;
GtkWidget *pFrame;
GtkWidget *pLabel;
GtkWidget *pScale;
gtk_init(&argc,&argv);
pWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(pWindow), "GtkScale");
gtk_window_set_default_size(GTK_WINDOW(pWindow), 320, 200);
gtk_container_set_border_width(GTK_CONTAINER(pWindow), 4);
pMainVBox = gtk_vbox_new(TRUE, 0);
gtk_container_add(GTK_CONTAINER(pWindow), pMainVBox);
pFrame = gtk_frame_new("Rouge");
/* Creation du widget GtkHScale */
pScale = gtk_hscale_new_with_range(0, 255, 1);
gtk_container_add(GTK_CONTAINER(pFrame), pScale);
gtk_box_pack_start(GTK_BOX(pMainVBox), pFrame, FALSE, FALSE, 0);
pFrame = gtk_frame_new("Vert");
pScale = gtk_hscale_new_with_range(0, 255, 1);
/* Position du label en dessous */
gtk_scale_set_value_pos(GTK_SCALE(pScale), GTK_POS_BOTTOM);
gtk_container_add(GTK_CONTAINER(pFrame), pScale);
gtk_box_pack_start(GTK_BOX(pMainVBox), pFrame, FALSE, FALSE, 0);
pFrame = gtk_frame_new("Bleu");
pScale = gtk_hscale_new_with_range(0, 255, 1);
/* Pas d'affichage du label */
gtk_scale_set_draw_value(GTK_SCALE(pScale), FALSE);
gtk_container_add(GTK_CONTAINER(pFrame), pScale);
gtk_box_pack_start(GTK_BOX(pMainVBox), pFrame, FALSE, FALSE, 0);
gtk_widget_show_all(pWindow);
g_signal_connect(G_OBJECT(pWindow), "destroy", G_CALLBACK(gtk_main_quit), NULL);
gtk_main();
return EXIT_SUCCESS;
}Résultat

Ce widget est un peu différent des deux précédents dans le sens ou il s'agit en fait d'un widget
GtkEntry et de deux
GtkButton assemblés pour former un tout. De plus il permet de sélectionner une valeur soit en utilisant les boutons soit en entrant directement la valeur au clavier. Mais voyons tout cela en détail.
5.1 Création
Il existe là aussi deux fonctions de créations :
GtkWidget* gtk_spin_button_new (GtkAdjustment? *adjustment, gdouble climb_rate, guint digits);
GtkWidget* gtk_spin_button_new_with_range (gdouble min, gdouble max, gdouble step);
La première fonction permet de créer un
GtkSpinButton à partir d'un
GtkAdjustment?, mais il faut cependant préciser le paramètre
climb_rate qui correspond au paramètre
step_increment du
GtkAdjustment? et
digits qui représente le nombre de chiffre après la virgule de la valeur que nous allons pouvoir sélectionner.
La deuxième fonction permet de se passer de
GtkAdjustment? car nous fixons les valeurs minimales et maximales (paramètres
min et
max) ainsi que la valeur de modification avec le paramètre
step. En ce qui concerne le nombre de chiffres après la virgule, il sera identique à celui de
step.
Pour ce widget, le clavier permet aussi de modifier sa valeur. Les touches fléchées HAUT et BAS permettent de modifier la valeur de
step_increment (dans le cas de l'utilisation d'un
GtkAdjustment?) ou de
step. De plus les touches PAGE_UP et PAGE_DOWN permettent de modifier la valeur de
page_increment avec une création utilisant un
GtkAdjustment? ou de step*10 dans l'autre cas.
5.2 Gestion des valeurs
Voyons tout d'abord comment récupérer ou modifier la valeur en cours d'un
GtkSpinButton à l'aide d'une de ces trois fonctions :
void gtk_spin_button_set_value (GtkSpinButton *spin_button, gdouble value);
gdouble gtk_spin_button_get_value (GtkSpinButton *spin_button);
gint gtk_spin_button_get_value_as_int(GtkSpinButton *spin_button);
La première fonction permet donc de modifier la valeur d'un
GtkSpinButton. Il faut pour le premier paramètre utiliser la macro de conversion GTK_SPIN_BUTTON().
La deuxième fonction permet de récupérer la valeur d'un
GtkSpinButton tout simplement.
La dernière fonction a le même but que la deuxième mais celle-ci renvoie un entier alors que la deuxième renvoie un double.
Nous pouvons nous occuper du nombre de chiffre après la virgule avec ces deux fonctions :
guint gtk_spin_button_get_digits (GtkSpinButton *spin_button);
void gtk_spin_button_set_digits (GtkSpinButton *spin_button, guint digits);
La première fonction permettant de connaître le nombre de chiffre après la virgule alors que la seconde permet de le modifier.
Et pour terminer voici les fonctions qui permettent de modifier les bornes des valeurs :
void gtk_spin_button_get_range (GtkSpinButton *spin_button, gdouble *min, gdouble *max);
void gtk_spin_button_set_range (GtkSpinButton *spin_button, gdouble min, gdouble max);
Comme d'habitude, la première fonction permet de connaître les bornes du
GtkSpinButton et la seconde permet de les modifier.
Mais bien sûr, tout cela peut se modifier à l'aide des
GtkAdjustment? avec ces deux fonctions :
GtkAdjustment?* gtk_spin_button_get_adjustment(GtkSpinButton *spin_button);
void gtk_spin_button_set_adjustment (GtkSpinButton *spin_button, GtkAdjustment? *adjustment);
5.3 Exemple
Le programme exemple sera identique aux deux premiers, c'est à dire qu'il va permettre de sélectionner une valeur RGB à l'aide de trois widget
GtkSpinButton.
5.4 Programme exemple
#include <stdlib.h>
#include <gtk/gtk.h>
int main(int argc,char **argv)
{
GtkWidget* pWindow;
GtkWidget *pMainVBox;
GtkWidget *pFrame;
GtkWidget *pSpin;
gtk_init(&argc,&argv);
pWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(pWindow), "GtkSpinButton");
gtk_window_set_default_size(GTK_WINDOW(pWindow), 320, 200);
gtk_container_set_border_width(GTK_CONTAINER(pWindow), 4);
pMainVBox = gtk_vbox_new(TRUE, 0);
gtk_container_add(GTK_CONTAINER(pWindow), pMainVBox);
pFrame = gtk_frame_new("Rouge");
/* Creation du widget GtkSpinButton */
pSpin = gtk_spin_button_new_with_range(0, 255, 1);
gtk_container_add(GTK_CONTAINER(pFrame), pSpin);
gtk_box_pack_start(GTK_BOX(pMainVBox), pFrame, FALSE, FALSE, 0);
pFrame = gtk_frame_new("Vert");
pSpin = gtk_spin_button_new_with_range(0, 255, 1);
gtk_container_add(GTK_CONTAINER(pFrame), pSpin);
gtk_box_pack_start(GTK_BOX(pMainVBox), pFrame, FALSE, FALSE, 0);
pFrame = gtk_frame_new("Bleu");
pSpin = gtk_spin_button_new_with_range(0, 255, 1);
gtk_container_add(GTK_CONTAINER(pFrame), pSpin);
gtk_box_pack_start(GTK_BOX(pMainVBox), pFrame, FALSE, FALSE, 0);
gtk_widget_show_all(pWindow);
g_signal_connect(G_OBJECT(pWindow), "destroy", G_CALLBACK(gtk_main_quit), NULL);
gtk_main();
return EXIT_SUCCESS;
}Résultat
