9.10. Botones Aumentar/Disminuir

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.

Recuerda 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:

valuevalor inicial para el Botón Aumentar/Disminuir
lowerel valor más bajo del rango
upperel valor más alto del rango
step_incrementvalor que se incrementa/decrementa cuando se pulsa el botón-1 del ratón en un botón
page_incrementvalor que se incrementa/decrementa cuando se pulsa el botón-2 del ratón en un botón
page_sizeno se usa

Adicionalmente, el botón del ratón botón-3 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 esta 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 intentaré explicar 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 de un control SpinButton propiamente.

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, puedes especificar una actualización por ti mismo SpinButton :

  spin_button.update()

El programa de ejemplo spinbutton.py muestra el uso de botones de aumentar/disminuir incluyendo el uso de un número de características. La figura Figura 9.11. Ejemplo de Botón Aumentar/Disminuir muestra el resultado de ejecutar el programa de ejemplo:

Figura 9.11. Ejemplo de Botón Aumentar/Disminuir

Ejemplo de Botón Aumentar/Disminuir

El código fuente spinbutton.py es:

    1   #!/usr/bin/env python
    2   
    3   # example spinbutton.py
    4	
    5	import gtk
    6	
    7	class SpinButtonExample:
    8	    def toggle_snap(self, widget, spin):
    9	        spin.set_snap_to_ticks(widget.get_active())
   10	
   11	    def toggle_numeric(self, widget, spin):
   12	        spin.set_numeric(widget.get_active())
   13	
   14	    def change_digits(self, widget, spin, spin1):
   15	        spin1.set_digits(spin.get_value_as_int())
   16	
   17	    def get_value(self, widget, data, spin, spin2, label):
   18	        if data == 1:
   19	            buf = "%d" % spin.get_value_as_int()
   20	        else:
   21	            buf = "%0.*f" % (spin2.get_value_as_int(),
   22	                             spin.get_value())
   23	        label.set_text(buf)
   24	
   25	    def __init__(self):
   26	        window = gtk.Window(gtk.WINDOW_TOPLEVEL)
   27	        window.connect("destroy", gtk.mainquit)
   28	        window.set_title("Spin Button")
   29	
   30	        main_vbox = gtk.VBox(gtk.FALSE, 5)
   31	        main_vbox.set_border_width(10)
   32	        window.add(main_vbox)
   33	
   34	        frame = gtk.Frame("Not accelerated")
   35	        main_vbox.pack_start(frame, gtk.TRUE, gtk.TRUE, 0)
   36	  
   37	        vbox = gtk.VBox(gtk.FALSE, 0)
   38	        vbox.set_border_width(5)
   39	        frame.add(vbox)
   40	
   41	        # Day, month, year spinners
   42	        hbox = gtk.HBox(gtk.FALSE, 0)
   43	        vbox.pack_start(hbox, gtk.TRUE, gtk.TRUE, 5)
   44	  
   45	        vbox2 = gtk.VBox(gtk.FALSE, 0)
   46	        hbox.pack_start(vbox2, gtk.TRUE, gtk.TRUE, 5)
   47	
   48	        label = gtk.Label("Day :")
   49	        label.set_alignment(0, 0.5)
   50	        vbox2.pack_start(label, gtk.FALSE, gtk.TRUE, 0)
   51	  
   52	        adj = gtk.Adjustment(1.0, 1.0, 31.0, 1.0, 5.0, 0.0)
   53	        spinner = gtk.SpinButton(adj, 0, 0)
   54	        spinner.set_wrap(gtk.TRUE)
   55	        vbox2.pack_start(spinner, gtk.FALSE, gtk.TRUE, 0)
   56	  
   57	        vbox2 = gtk.VBox(gtk.FALSE, 0)
   58	        hbox.pack_start(vbox2, gtk.TRUE, gtk.TRUE, 5)
   59	  
   60	        label = gtk.Label("Month :")
   61	        label.set_alignment(0, 0.5)
   62	        vbox2.pack_start(label, gtk.FALSE, gtk.TRUE, 0)
   63	
   64	        adj = gtk.Adjustment(1.0, 1.0, 12.0, 1.0, 5.0, 0.0)
   65	        spinner = gtk.SpinButton(adj, 0, 0)
   66	        spinner.set_wrap(gtk.TRUE)
   67	        vbox2.pack_start(spinner, gtk.FALSE, gtk.TRUE, 0)
   68	  
   69	        vbox2 = gtk.VBox(gtk.FALSE, 0)
   70	        hbox.pack_start(vbox2, gtk.TRUE, gtk.TRUE, 5)
   71	  
   72	        label = gtk.Label("Year :")
   73	        label.set_alignment(0, 0.5)
   74	        vbox2.pack_start(label, gtk.FALSE, gtk.TRUE, 0)
   75	  
   76	        adj = gtk.Adjustment(1998.0, 0.0, 2100.0, 1.0, 100.0, 0.0)
   77	        spinner = gtk.SpinButton(adj, 0, 0)
   78	        spinner.set_wrap(gtk.FALSE)
   79	        spinner.set_size_request(55, -1)
   80	        vbox2.pack_start(spinner, gtk.FALSE, gtk.TRUE, 0)
   81	  
   82	        frame = gtk.Frame("Accelerated")
   83	        main_vbox.pack_start(frame, gtk.TRUE, gtk.TRUE, 0)
   84	  
   85	        vbox = gtk.VBox(gtk.FALSE, 0)
   86	        vbox.set_border_width(5)
   87	        frame.add(vbox)
   88	  
   89	        hbox = gtk.HBox(gtk.FALSE, 0)
   90	        vbox.pack_start(hbox, gtk.FALSE, gtk.TRUE, 5)
   91	  
   92	        vbox2 = gtk.VBox(gtk.FALSE, 0)
   93	        hbox.pack_start(vbox2, gtk.TRUE, gtk.TRUE, 5)
   94	  
   95	        label = gtk.Label("Value :")
   96	        label.set_alignment(0, 0.5)
   97	        vbox2.pack_start(label, gtk.FALSE, gtk.TRUE, 0)
   98	  
   99	        adj = gtk.Adjustment(0.0, -10000.0, 10000.0, 0.5, 100.0, 0.0)
  100	        spinner1 = gtk.SpinButton(adj, 1.0, 2)
  101	        spinner1.set_wrap(gtk.TRUE)
  102	        spinner1.set_size_request(100, -1)
  103	        vbox2.pack_start(spinner1, gtk.FALSE, gtk.TRUE, 0)
  104	  
  105	        vbox2 = gtk.VBox(gtk.FALSE, 0)
  106	        hbox.pack_start(vbox2, gtk.TRUE, gtk.TRUE, 5)
  107	  
  108	        label = gtk.Label("Digits :")
  109	        label.set_alignment(0, 0.5)
  110	        vbox2.pack_start(label, gtk.FALSE, gtk.TRUE, 0)
  111	  
  112	        adj = gtk.Adjustment(2, 1, 5, 1, 1, 0)
  113	        spinner2 = gtk.SpinButton(adj, 0.0, 0)
  114	        spinner2.set_wrap(gtk.TRUE)
  115	        adj.connect("value_changed", self.change_digits, spinner2, spinner1)
  116	        vbox2.pack_start(spinner2, gtk.FALSE, gtk.TRUE, 0)
  117	  
  118	        hbox = gtk.HBox(gtk.FALSE, 0)
  119	        vbox.pack_start(hbox, gtk.FALSE, gtk.TRUE, 5)
  120	
  121	        button = gtk.CheckButton("Snap to 0.5-ticks")
  122	        button.connect("clicked", self.toggle_snap, spinner1)
  123	        vbox.pack_start(button, gtk.TRUE, gtk.TRUE, 0)
  124	        button.set_active(gtk.TRUE)
  125	  
  126	        button = gtk.CheckButton("Numeric only input mode")
  127	        button.connect("clicked", self.toggle_numeric, spinner1)
  128	        vbox.pack_start(button, gtk.TRUE, gtk.TRUE, 0)
  129	        button.set_active(gtk.TRUE)
  130	  
  131	        val_label = gtk.Label("")
  132	  
  133	        hbox = gtk.HBox(gtk.FALSE, 0)
  134	        vbox.pack_start(hbox, gtk.FALSE, gtk.TRUE, 5)
  135	        button = gtk.Button("Value as Int")
  136	        button.connect("clicked", self.get_value, 1, spinner1, spinner2,
  137	                       val_label)
  138	        hbox.pack_start(button, gtk.TRUE, gtk.TRUE, 5)
  139	  
  140	        button = gtk.Button("Value as Float")
  141	        button.connect("clicked", self.get_value, 2, spinner1, spinner2,
  142	                       val_label)
  143	        hbox.pack_start(button, gtk.TRUE, gtk.TRUE, 5)
  144	  
  145	        vbox.pack_start(val_label, gtk.TRUE, gtk.TRUE, 0)
  146	        val_label.set_text("0")
  147	  
  148	        hbox = gtk.HBox(gtk.FALSE, 0)
  149	        main_vbox.pack_start(hbox, gtk.FALSE, gtk.TRUE, 0)
  150	  
  151	        button = gtk.Button("Close")
  152	        button.connect("clicked", gtk.mainquit)
  153	        hbox.pack_start(button, gtk.TRUE, gtk.TRUE, 5)
  154	        window.show_all()
  155	
  156	def main():
  157	    gtk.main()
  158	    return 0
  159	
  160	if __name__ == "__main__":
  161	    SpinButtonExample()
  162	    main()