El control SpinButton (Botón Aumentar/ Disminuir) se usa generalmente para permitir al usuario seleccionar un valor dentro de un rango de valores numéricos. Consiste en una caja de entrada de texto con botones de flecha arriba y abajo a un lado. Seleccionando uno de los botones causa que el valor aumente o disminuya en el rango de valores posibles. La caja de entrada también puede editarse directamente para introducir un valor específico.
El SpinButton permite que el valor tenga cero o más cifras decimales y puede incrementarse/decrementarse en pasos configurables. La acción de mantener pulsado uno de los botones opcionalmente provoca una aceleración en el cambio del valor correspondiente al tiempo que se mantenga presionado.
El SpinButton usa un objeto Adjustment (Ajuste) para almacenar la información del rango de valores que el botón aumentar/disminuir puede tomar. Esto le hace un control muy útil.
Recordemos que un control Adjustment (Ajuste) se crea con la siguiente función, que muestra la información que almacena:
adjustment = gtk.Adjustment(value=0, lower=0, upper=0, step_incr=0, page_incr=0, page_size=0) |
Estos atributos de un Adjustment (Ajuste) se usan en el SpinButton de la siguiente manera:
| value | valor inicial para el Botón Aumentar/Disminuir |
| lower | el valor más bajo del rango |
| upper | el valor más alto del rango |
| step_increment | valor que se incrementa/decrementa cuando se pulsa el del ratón en un botón |
| page_increment | valor que se incrementa/decrementa cuando se pulsa el del ratón en un botón |
| page_size | no se usa |
Adicionalmente, el botón del ratón se puede usar para saltar directamente a los valores upper (superior) y lower (inferior) cuando se usa para seleccionar uno de los botones. Veamos como crear un SpinButton (Botón Aumentar/Disminuir):
spin_button = gtk.SpinButton(adjustment=None, climb_rate=0.0, digits=0) |
El argumento climb_rate (razón de escalada) puede tomar un valor entre 0.0 y 1.0 e indica la cantidad de aceleración que el SpinButton tiene. El argumento digits especifica el número de cifras decimales que se mostrarán.
Un SpinButton se puede reconfigurar después de su creación usando el siguiente método:
spin_button.configure(adjustment, climb_rate, digits) |
La variable spin_button especifica el botón aumentar/disminuir que se va a reconfigurar. Los otros argumentos son los mismos que antes.
El adjustment (ajuste) se puede fijar y recupar independientemente usando los siguientes dos métodos:
spin_button.set_adjustment(adjustment) adjustment = spin_button.get_adjustment() |
El número de cifras decimales también se puede cambiar usando:
spin_button.set_digits(digits) |
El valor que un SpinButton está mostrando actualmente se puede cambiar usando el siguiente método:
spin_button.set_value(value) |
El valor actual de un SpinButton se puede recuperar como un valor real o como un valor entero usando los siguientes métodos:
float_value = spin_button.get_value() int_value = spin_button.get_value_as_int() |
Si quieres alterar el valor de un SpinButton relativo a su valor actual, entonces usa el siguiente método:
spin_button.spin(direction, increment) |
El parámetro direction (dirección) puede tomar uno de los siguientes valores:
SPIN_STEP_FORWARD # paso hacia adelante SPIN_STEP_BACKWARD # paso hacia atrás SPIN_PAGE_FORWARD # página hacia adelante SPIN_PAGE_BACKWARD # página hacia atrás SPIN_HOME # inicio SPIN_END # fin SPIN_USER_DEFINED # definido por el usuario |
Este método comprime bastante funcionalidad, que explicaremos ahora. Muchos de estos parámetros usan valores del objeto Adjustment (Ajuste) que está asociado con un SpinButton (Botón Aumentar/Disminuir).
SPIN_STEP_FORWARD (paso adelante) y SPIN_STEP_BACKWARD (paso atrás) cambian el valor del SpinButton con una cantidad especificada por el increment (incremento), a menos que increment (incremento) sea igual a 0, en cuyo caso el valor se modifica con el step_increment (incremento de paso) del Adjustment.
SPIN_PAGE_FORWARD (página adelante) y SPIN_PAGE_BACKWARD (página atrás) simplemente alteran el valor del SpinButton por increment (incremento).
SPIN_HOME (inicio) pone el valor del SpinButton a la parte de abajo del rango del Adjustment .
SPIN_END (fin) fija el valor del SpinButton a la parte de arriba del rango del Adjustment .
SPIN_USER_DEFINED (definido por el usuario) simplemente modifica el valor del SpinButton con la cantidad especificada.
Ahora nos alejamos de los métodos para fijar y recuperar los atributos del rango de un SpinButton, y nos centramos en los métodos que modifican la apariencia y comportamiento del propio control SpinButton.
El primero de estos métodos se usa para limitar la caja de texto del SpinButton para que solo contenga un valor numérico. Esto evita que el usuario escriba cualquier otra cosa que no sea un valor numérico dentro de la caja de texto de un SpinButton:
spin_button.set_numeric(numeric) |
El argumento numeric es TRUE para limitar la caja de texto a valores numéricos o FALSE para quitar esta limitación.
Puedes fijar si quieres que el valor del SpinButton se quede en los valores inferior y superior del rango con el siguiente método:
spin_button.set_wrap(wrap) |
El SpinButton limitará los valores dentro del rango si wrap es TRUE.
Puedes hacer que el SpinButton redondee el valor al step_increment (incremento) más cercano, lo cual se fija dentro del objeto Adjustment usado en el SpinButton. Esto se consigue con el siguiente método cuando el argumento snap_to_ticks es TRUE :
spin_button.set_snap_to_ticks(snap_to_ticks) |
La política de actualización de un SpinButton se cambia con el siguiente método:
spin_button.set_update_policy(policy) |
Los valores posibles de esta política son:
UPDATE_ALWAYS # actualizar siempre UPDATE_IF_VALID # actualizar si es válido |
Estas políticas afectan el comportamiento de un SpinButton cuando analiza el texto insertado y sincroniza su valor con los valores del Adjustment.
En el caso de UPDATE_IF_VALID (actualizar si es válido) el valor del SpinButton sólo cambia si el texto es un valor numérico que está dentro del rango especificado por el Adjustment. En cualquier otro caso el texto se resetea al valor actual.
En el caso de UPDATE_ALWAYS (actualizar siempre) se ignoran los errores de conversión al pasar el texto a un valor numérico.
Finalmente, se puede solicitar una actualización del SpinButton :
spin_button.update() |
El programa de ejemplo spinbutton.py muestra el uso de botones de aumentar/disminuir incluyendo el uso de varias características. La figura Figura 9.11, “Ejemplo de Botón Aumentar/Disminuir” muestra el resultado de ejecutar el programa de ejemplo:
El código fuente spinbutton.py es:
1 #!/usr/bin/env python
2
3 # ejemplo spinbutton.py
4
5 import pygtk
6 pygtk.require('2.0')
7 import gtk
8
9 class SpinButtonExample:
10 def toggle_snap(self, widget, spin):
11 spin.set_snap_to_ticks(widget.get_active())
12
13 def toggle_numeric(self, widget, spin):
14 spin.set_numeric(widget.get_active())
15
16 def change_digits(self, widget, spin, spin1):
17 spin1.set_digits(spin.get_value_as_int())
18
19 def get_value(self, widget, data, spin, spin2, label):
20 if data == 1:
21 buf = "%d" % spin.get_value_as_int()
22 else:
23 buf = "%0.*f" % (spin2.get_value_as_int(),
24 spin.get_value())
25 label.set_text(buf)
26
27 def __init__(self):
28 window = gtk.Window(gtk.WINDOW_TOPLEVEL)
29 window.connect("destroy", lambda w: gtk.main_quit())
30 window.set_title("Spin Button")
31
32 main_vbox = gtk.VBox(gtk.FALSE, 5)
33 main_vbox.set_border_width(10)
34 window.add(main_vbox)
35
36 frame = gtk.Frame("Not accelerated")
37 main_vbox.pack_start(frame, gtk.TRUE, gtk.TRUE, 0)
38
39 vbox = gtk.VBox(gtk.FALSE, 0)
40 vbox.set_border_width(5)
41 frame.add(vbox)
42
43 # Botones de aumentar/disminuir día, mes y año
44 hbox = gtk.HBox(gtk.FALSE, 0)
45 vbox.pack_start(hbox, gtk.TRUE, gtk.TRUE, 5)
46
47 vbox2 = gtk.VBox(gtk.FALSE, 0)
48 hbox.pack_start(vbox2, gtk.TRUE, gtk.TRUE, 5)
49
50 label = gtk.Label("Day :")
51 label.set_alignment(0, 0.5)
52 vbox2.pack_start(label, gtk.FALSE, gtk.TRUE, 0)
53
54 adj = gtk.Adjustment(1.0, 1.0, 31.0, 1.0, 5.0, 0.0)
55 spinner = gtk.SpinButton(adj, 0, 0)
56 spinner.set_wrap(gtk.TRUE)
57 vbox2.pack_start(spinner, gtk.FALSE, gtk.TRUE, 0)
58
59 vbox2 = gtk.VBox(gtk.FALSE, 0)
60 hbox.pack_start(vbox2, gtk.TRUE, gtk.TRUE, 5)
61
62 label = gtk.Label("Month :")
63 label.set_alignment(0, 0.5)
64 vbox2.pack_start(label, gtk.FALSE, gtk.TRUE, 0)
65
66 adj = gtk.Adjustment(1.0, 1.0, 12.0, 1.0, 5.0, 0.0)
67 spinner = gtk.SpinButton(adj, 0, 0)
68 spinner.set_wrap(gtk.TRUE)
69 vbox2.pack_start(spinner, gtk.FALSE, gtk.TRUE, 0)
70
71 vbox2 = gtk.VBox(gtk.FALSE, 0)
72 hbox.pack_start(vbox2, gtk.TRUE, gtk.TRUE, 5)
73
74 label = gtk.Label("Year :")
75 label.set_alignment(0, 0.5)
76 vbox2.pack_start(label, gtk.FALSE, gtk.TRUE, 0)
77
78 adj = gtk.Adjustment(1998.0, 0.0, 2100.0, 1.0, 100.0, 0.0)
79 spinner = gtk.SpinButton(adj, 0, 0)
80 spinner.set_wrap(gtk.FALSE)
81 spinner.set_size_request(55, -1)
82 vbox2.pack_start(spinner, gtk.FALSE, gtk.TRUE, 0)
83
84 frame = gtk.Frame("Accelerated")
85 main_vbox.pack_start(frame, gtk.TRUE, gtk.TRUE, 0)
86
87 vbox = gtk.VBox(gtk.FALSE, 0)
88 vbox.set_border_width(5)
89 frame.add(vbox)
90
91 hbox = gtk.HBox(gtk.FALSE, 0)
92 vbox.pack_start(hbox, gtk.FALSE, gtk.TRUE, 5)
93
94 vbox2 = gtk.VBox(gtk.FALSE, 0)
95 hbox.pack_start(vbox2, gtk.TRUE, gtk.TRUE, 5)
96
97 label = gtk.Label("Value :")
98 label.set_alignment(0, 0.5)
99 vbox2.pack_start(label, gtk.FALSE, gtk.TRUE, 0)
100
101 adj = gtk.Adjustment(0.0, -10000.0, 10000.0, 0.5, 100.0, 0.0)
102 spinner1 = gtk.SpinButton(adj, 1.0, 2)
103 spinner1.set_wrap(gtk.TRUE)
104 spinner1.set_size_request(100, -1)
105 vbox2.pack_start(spinner1, gtk.FALSE, gtk.TRUE, 0)
106
107 vbox2 = gtk.VBox(gtk.FALSE, 0)
108 hbox.pack_start(vbox2, gtk.TRUE, gtk.TRUE, 5)
109
110 label = gtk.Label("Digits :")
111 label.set_alignment(0, 0.5)
112 vbox2.pack_start(label, gtk.FALSE, gtk.TRUE, 0)
113
114 adj = gtk.Adjustment(2, 1, 5, 1, 1, 0)
115 spinner2 = gtk.SpinButton(adj, 0.0, 0)
116 spinner2.set_wrap(gtk.TRUE)
117 adj.connect("value_changed", self.change_digits, spinner2, spinner1)
118 vbox2.pack_start(spinner2, gtk.FALSE, gtk.TRUE, 0)
119
120 hbox = gtk.HBox(gtk.FALSE, 0)
121 vbox.pack_start(hbox, gtk.FALSE, gtk.TRUE, 5)
122
123 button = gtk.CheckButton("Snap to 0.5-ticks")
124 button.connect("clicked", self.toggle_snap, spinner1)
125 vbox.pack_start(button, gtk.TRUE, gtk.TRUE, 0)
126 button.set_active(gtk.TRUE)
127
128 button = gtk.CheckButton("Numeric only input mode")
129 button.connect("clicked", self.toggle_numeric, spinner1)
130 vbox.pack_start(button, gtk.TRUE, gtk.TRUE, 0)
131 button.set_active(gtk.TRUE)
132
133 val_label = gtk.Label("")
134
135 hbox = gtk.HBox(gtk.FALSE, 0)
136 vbox.pack_start(hbox, gtk.FALSE, gtk.TRUE, 5)
137 button = gtk.Button("Value as Int")
138 button.connect("clicked", self.get_value, 1, spinner1, spinner2,
139 val_label)
140 hbox.pack_start(button, gtk.TRUE, gtk.TRUE, 5)
141
142 button = gtk.Button("Value as Float")
143 button.connect("clicked", self.get_value, 2, spinner1, spinner2,
144 val_label)
145 hbox.pack_start(button, gtk.TRUE, gtk.TRUE, 5)
146
147 vbox.pack_start(val_label, gtk.TRUE, gtk.TRUE, 0)
148 val_label.set_text("0")
149
150 hbox = gtk.HBox(gtk.FALSE, 0)
151 main_vbox.pack_start(hbox, gtk.FALSE, gtk.TRUE, 0)
152
153 button = gtk.Button("Close")
154 button.connect("clicked", lambda w: gtk.main_quit())
155 hbox.pack_start(button, gtk.TRUE, gtk.TRUE, 5)
156 window.show_all()
157
158 def main():
159 gtk.main()
160 return 0
161
162 if __name__ == "__main__":
163 SpinButtonExample()
164 main()
|