Cómo controlar la entrada numérica utilizando el widget Spinbox en Python

Tkinter es la biblioteca estándar de GUI de Python y ofrece una variedad de widgets. Entre ellos, el Spinbox es un widget muy útil cuando se desea limitar la entrada de números o cadenas. En este artículo, se explica ampliamente el uso básico del Spinbox, ejemplos avanzados y cómo lograr un control de entrada. Al usar Spinbox, puede controlar fácilmente los valores que los usuarios pueden ingresar, lo que ayuda a crear aplicaciones seguras y eficientes.

Índice

Uso básico del Spinbox


El Spinbox es uno de los widgets proporcionados por Tkinter que permite al usuario seleccionar o ingresar valores dentro de un rango especificado. A continuación se muestra cómo usarlo de manera básica.

Crear un Spinbox


Un Spinbox se crea utilizando la clase Spinbox. A continuación se muestra un ejemplo de código que muestra un Spinbox simple.

import tkinter as tk

# Crear ventana Tkinter
root = tk.Tk()
root.title("Ejemplo básico de Spinbox")

# Crear un Spinbox
spinbox = tk.Spinbox(root, from_=0, to=10)
spinbox.pack()

# Iniciar el bucle principal
root.mainloop()

Explicación del código

  1. Opciones from_ y to
  • from_ especifica el valor mínimo del Spinbox.
  • to especifica el valor máximo del Spinbox.
    En este ejemplo, los valores que se pueden seleccionar son del 0 al 10.
  1. Método pack()
  • Se usa para colocar el Spinbox en la ventana.

Verificación del funcionamiento


Al ejecutar el código anterior, aparecerá un Spinbox con valores de 0 a 10, y el usuario podrá seleccionar un valor usando los botones de flecha.

La siguiente sección explica cómo configurar un rango más detallado de valores que se pueden ingresar en el Spinbox.

Cómo establecer un rango de valores


En un Spinbox, puedes especificar un rango de valores que el usuario puede ingresar. Al hacer esto correctamente, puedes prevenir la entrada de valores inesperados y garantizar una entrada de datos segura y eficiente.

Especificación de rango usando from_ y to


Usando las opciones from_ y to del Spinbox, puedes establecer los valores mínimo y máximo que se pueden ingresar.

import tkinter as tk

# Crear ventana Tkinter
root = tk.Tk()
root.title("Configuración de rango de valores")

# Crear un Spinbox con un rango de 1 a 100
spinbox = tk.Spinbox(root, from_=1, to=100)
spinbox.pack()

# Iniciar el bucle principal
root.mainloop()

En este ejemplo, los valores que se pueden ingresar están entre 1 y 100. Si el usuario intenta ingresar un valor fuera de este rango, el Spinbox no lo aceptará.

Configurar tamaño del paso


La opción increment permite configurar la cantidad de cambio (tamaño del paso) cuando se cambia el valor del Spinbox.

spinbox = tk.Spinbox(root, from_=0, to=50, increment=5)

Con esta configuración, los valores cambian de 5 en 5 dentro del rango de 0 a 50 (0, 5, 10, …).

Especificar valores desde una lista


Si solo deseas permitir ciertos valores, puedes usar la opción values para establecer una lista de opciones.

spinbox = tk.Spinbox(root, values=(10, 20, 30, 40, 50))

En este ejemplo, solo los valores 10, 20, 30, 40 y 50 son seleccionables.

Cambiar dinámicamente el rango


También puedes cambiar dinámicamente el rango o los valores del Spinbox en tu programa. A continuación se muestra un ejemplo de cómo cambiar el rango dinámicamente.

def update_range():
    spinbox.config(from_=50, to=200)

button = tk.Button(root, text="Cambiar rango", command=update_range)
button.pack()

Usando el método config, puedes modificar fácilmente las propiedades del Spinbox.

En la siguiente sección, veremos cómo validar los valores del Spinbox en tiempo real.

Validar la entrada usando funciones de retorno (callback)


Validar los valores del Spinbox en tiempo real ayuda a prevenir entradas no válidas y a crear aplicaciones más robustas y seguras. En Tkinter, puedes usar funciones de retorno para realizar esta validación.

Registrar una función de retorno


Para registrar una función de retorno que se llama cuando el valor del Spinbox cambia, usa la opción command.

import tkinter as tk

# Función de retorno
def on_value_change():
    value = spinbox.get()
    print(f"Valor actual: {value}")

# Crear ventana Tkinter
root = tk.Tk()
root.title("Ejemplo de función de retorno")

# Crear Spinbox
spinbox = tk.Spinbox(root, from_=0, to=10, command=on_value_change)
spinbox.pack()

# Iniciar el bucle principal
root.mainloop()

Este código llama a la función on_value_change cada vez que el valor del Spinbox cambia, imprimiendo el valor actual.

Agregar validación de valores


Para validar si el valor ingresado cumple con ciertos criterios, puedes analizar y verificar el valor.

def validate_value():
    value = int(spinbox.get())
    if value % 2 == 0:
        print(f"{value} es par.")
    else:
        print(f"{value} es impar.")

Si registras esta función con la opción command, la condición será verificada cada vez que el valor del Spinbox cambie.

Uso de validate y validatecommand


Para una validación más estricta, combina las opciones validate y validatecommand.

def validate_input(value):
    return value.isdigit() and 0 <= int(value) <= 10

# Registrar comando de validación de Tkinter
vcmd = root.register(validate_input)

spinbox = tk.Spinbox(root, from_=0, to=10, validate="key", validatecommand=(vcmd, '%P'))
spinbox.pack()

Puntos clave del código

  • validate="key": Configura la validación al ingresar desde el teclado.
  • validatecommand: Especifica la función para realizar la validación.
  • '%P': Pasa el valor actual de la entrada a la función de validación.

Este ejemplo verifica si la entrada es un número dentro del rango de 0 a 10, evitando entradas no válidas.

Mostrar mensajes de error


A continuación se muestra un ejemplo de cómo mostrar un mensaje de error si el valor ingresado no cumple con los criterios.

def validate_and_alert(value):
    if not value.isdigit() or not (0 <= int(value) <= 10):
        error_label.config(text="Por favor, ingrese un valor entre 0 y 10")
        return False
    error_label.config(text="")
    return True

vcmd = root.register(validate_and_alert)

spinbox = tk.Spinbox(root, from_=0, to=10, validate="key", validatecommand=(vcmd, '%P'))
spinbox.pack()

error_label = tk.Label(root, text="", fg="red")
error_label.pack()

Con esta configuración, cualquier entrada no válida es bloqueada y el mensaje de error se muestra de inmediato.

La siguiente sección cubre cómo restringir la entrada a números decimales o valores específicos.

Restricciones de entrada para valores decimales o específicos


De forma predeterminada, el Spinbox maneja solo números enteros, pero mediante configuraciones específicas puedes permitir valores decimales o restringir la entrada a ciertos valores. Esto te permite controlar la entrada de manera más flexible según la aplicación.

Permitir valores decimales


Si deseas permitir números decimales en el Spinbox, puedes usar la opción values para especificar una lista de valores permitidos.

import tkinter as tk

# Crear ventana Tkinter
root = tk.Tk()
root.title("Control de entrada decimal")

# Crear lista de valores decimales
decimal_values = [x / 10 for x in range(0, 101)]  # 0.0–10.0

# Crear Spinbox
spinbox = tk.Spinbox(root, values=decimal_values)
spinbox.pack()

# Iniciar el bucle principal
root.mainloop()

En este ejemplo, el Spinbox permite ingresar valores decimales como 0.0, 0.1, 0.2, …, 10.0. Al pasar una lista de valores a la opción values, puedes manejar números no enteros.

Permitir valores decimales especificando el tamaño del paso


También puedes permitir valores decimales usando las opciones from_, to y increment para definir el tamaño del paso.

spinbox = tk.Spinbox(root, from_=0, to=10, increment=0.1)
spinbox.pack()

Este código permite que los valores del Spinbox varíen de 0.0 a 10.0 en incrementos de 0.1.

Permitir solo valores específicos


Si solo deseas permitir ciertos valores, puedes especificar los valores permitidos en una lista usando la opción values.

spinbox = tk.Spinbox(root, values=(1.5, 2.5, 3.5, 4.5))
spinbox.pack()

Este código permite que solo los valores 1.5, 2.5, 3.5 y 4.5 sean seleccionables.

Combinación de validación flexible para restricciones de entrada


Si deseas limitar el número de decimales o permitir solo ciertos valores que cumplan con condiciones específicas, puedes combinar las opciones validate y validatecommand.

def validate_float(value):
    try:
        # Verificar que el valor sea un decimal dentro del rango
        float_value = float(value)
        return 0.0 <= float_value <= 10.0
    except ValueError:
        return False

vcmd = root.register(validate_float)

spinbox = tk.Spinbox(root, from_=0, to=10, validate="key", validatecommand=(vcmd, '%P'))
spinbox.pack()

Este código permite solo valores decimales válidos dentro del rango de 0.0 a 10.0.

Forzar el formato de entrada


Si deseas limitar la cantidad de dígitos decimales, puedes usar una función de retorno que formatee la entrada.

def format_input():
    value = spinbox.get()
    try:
        formatted_value = f"{float(value):.2f}"  # Formatear a 2 decimales
        spinbox.delete(0, tk.END)
        spinbox.insert(0, formatted_value)
    except ValueError:
        pass

spinbox = tk.Spinbox(root, from_=0, to=10, increment=0.01, command=format_input)
spinbox.pack()

Este código aplica un formato de 2 decimales cada vez que cambia el valor del Spinbox.

La siguiente sección explica cómo manipular el valor del Spinbox mediante botones.

Manipular el valor del Spinbox con botones


Manipular el valor del Spinbox dinámicamente mediante botones mejora la experiencia del usuario y es útil en ciertos escenarios. Puedes cambiar el valor sin que el usuario interactúe directamente con el Spinbox.

Obtener el valor del Spinbox


Para obtener el valor actual del Spinbox, usa el método get.

def get_value():
    value = spinbox.get()
    print(f"Valor actual: {value}")

button_get = tk.Button(root, text="Obtener valor", command=get_value)
button_get.pack()

Este código obtiene el valor actual del Spinbox y lo imprime cuando el usuario hace clic en el botón “Obtener valor”.

Configurar el valor del Spinbox


Usando los métodos delete e insert, puedes configurar el valor del Spinbox.

def set_value(new_value):
    spinbox.delete(0, tk.END)
    spinbox.insert(0, new_value)

button_set = tk.Button(root, text="Configurar valor", command=lambda: set_value(5))
button_set.pack()

Este código configura el valor del Spinbox a 5 cuando el usuario hace clic en el botón “Configurar valor”.

Crear botones de incremento y decremento


Para cambiar el valor del Spinbox con botones, puedes obtener el valor actual, calcular el nuevo valor y establecerlo.

def increment():
    value = int(spinbox.get())
    spinbox.delete(0, tk.END)
    spinbox.insert(0, value + 1)

def decrement():
    value = int(spinbox.get())
    spinbox.delete(0, tk.END)
    spinbox.insert(0, value - 1)

button_increment = tk.Button(root, text="Incrementar", command=increment)
button_increment.pack()

button_decrement = tk.Button(root, text="Decrementar", command=decrement)
button_decrement.pack()

Este código incrementa o decrementa el valor del Spinbox cuando se hace clic en los botones correspondientes.

Implementación teniendo en cuenta los límites del rango


Para evitar que el valor del Spinbox se establezca fuera del rango, debes considerar las opciones from_ y to al agregar la lógica de incremento y decremento.

def increment_safe():
    value = int(spinbox.get())
    if value < 10:  # Considerando el límite superior
        spinbox.delete(0, tk.END)
        spinbox.insert(0, value + 1)

def decrement_safe():
    value = int(spinbox.get())
    if value > 0:  # Considerando el límite inferior
        spinbox.delete(0, tk.END)
        spinbox.insert(0, value - 1)

button_increment_safe = tk.Button(root, text="Incrementar seguro", command=increment_safe)
button_increment_safe.pack()

button_decrement_safe = tk.Button(root, text="Decrementar seguro", command=decrement_safe)
button_decrement_safe.pack()

Este ejemplo previene que el valor del Spinbox se cambie fuera de su rango configurado.

Ejemplo avanzado: Restablecer al valor predeterminado


Puedes agregar funcionalidad para restablecer el valor del Spinbox a su valor inicial en ciertas condiciones.

def reset_value():
    spinbox.delete(0, tk.END)
    spinbox.insert(0, 0)

button_reset = tk.Button(root, text="Restablecer", command=reset_value)
button_reset.pack()

Este código restablece el valor del Spinbox a 0 cuando se hace clic en el botón “Restablecer”.

La siguiente sección aborda el uso del Spinbox para formularios.

Ejemplo práctico: Uso en formularios


El Spinbox puede ser útil en formularios cuando se requiere que el usuario ingrese un número o seleccione una opción de manera sencilla. Esta sección muestra cómo usar el Spinbox para crear formularios.

Ejemplo: Formulario de edad


Vamos a crear un formulario para que el usuario ingrese su edad utilizando un Spinbox.

import tkinter as tk

# Crear ventana Tkinter
root = tk.Tk()
root.title("Formulario de edad")

# Crear Spinbox para la edad
tk.Label(root, text="Ingrese su edad:").pack()
age_spinbox = tk.Spinbox(root, from_=0, to=120)
age_spinbox.pack()

# Acción del botón de envío
def submit_form():
    age = age_spinbox.get()
    result_label.config(text=f"Edad ingresada: {age}")

submit_button = tk.Button(root, text="Enviar", command=submit_form)
submit_button.pack()

# Etiqueta para mostrar el resultado
result_label = tk.Label(root, text="")
result_label.pack()

# Iniciar el bucle principal
root.mainloop()

Este código permite al usuario ingresar su edad mediante un Spinbox y muestra el valor ingresado cuando se hace clic en el botón “Enviar”.

Ejemplo: Uso en un formulario de reservas


Usamos un Spinbox para que el usuario seleccione la cantidad de personas y la hora para hacer una reserva.

# Crear ventana Tkinter
root = tk.Tk()
root.title("Formulario de reservas")

# Spinbox para el número de personas
tk.Label(root, text="Número de personas:").pack()
guest_spinbox = tk.Spinbox(root, from_=1, to=20)
guest_spinbox.pack()

# Spinbox para la hora de reserva
tk.Label(root, text="Hora de la reserva:").pack()
time_spinbox = tk.Spinbox(root, values=("12:00", "13:00", "14:00", "15:00", "16:00"))
time_spinbox.pack()

# Acción del botón de reserva
def submit_reservation():
    guests = guest_spinbox.get()
    time = time_spinbox.get()
    result_label.config(text=f"Reserva: {guests} personas a las {time}")

submit_button = tk.Button(root, text="Enviar reserva", command=submit_reservation)
submit_button.pack()

# Etiqueta para mostrar el resultado
result_label = tk.Label(root, text="")
result_label.pack()

# Iniciar el bucle principal
root.mainloop()

Este formulario permite seleccionar el número de personas y la hora de la reserva.

Ejemplo: Usar múltiples Spinboxes


Cuando es necesario ingresar información compleja, puedes combinar múltiples Spinboxes. A continuación se muestra un ejemplo para ingresar una fecha.

# Spinboxes para la fecha
tk.Label(root, text="Año:").pack()
year_spinbox = tk.Spinbox(root, from_=2000, to=2100)
year_spinbox.pack()

tk.Label(root, text="Mes:").pack()
month_spinbox = tk.Spinbox(root, from_=1, to=12)
month_spinbox.pack()

tk.Label(root, text="Día:").pack()
day_spinbox = tk.Spinbox(root, from_=1, to=31)
day_spinbox.pack()

def submit_date():
    year = year_spinbox.get()
    month = month_spinbox.get()
    day = day_spinbox.get()
    result_label.config(text=f"Fecha ingresada: {year}/{month}/{day}")

submit_button = tk.Button(root, text="Enviar fecha", command=submit_date)
submit_button.pack()

Este código permite seleccionar un año, mes y día mediante Spinboxes y luego mostrar la fecha completa.

Mejorando el diseño del formulario


Puedes mejorar el diseño de los formularios usando algunos puntos clave con Spinbox:

  • Colocación de etiquetas: Asegúrate de que las etiquetas estén bien ubicadas para que el usuario pueda reconocer fácilmente los campos de entrada.
  • Configuración de valores predeterminados: Reduce las opciones disponibles configurando valores predeterminados comunes.
  • Mostrar mensajes de error: Agrega mensajes de error para cuando la entrada no sea válida.

La siguiente sección explica cómo personalizar el Spinbox para que se ajuste mejor a tus necesidades.

Cómo personalizar el Spinbox


Al personalizar el aspecto y comportamiento del Spinbox, puedes adaptar el diseño y las funcionalidades a tu aplicación. Esta sección te muestra cómo hacerlo.

Cambiar fuentes y colores


Puedes cambiar la fuente, el color de fondo y el color del texto del Spinbox utilizando las opciones font, bg (fondo) y fg (texto).

import tkinter as tk

# Crear ventana Tkinter
root = tk.Tk()
root.title("Personalización del Spinbox")

# Crear un Spinbox con fuente y colores personalizados
spinbox = tk.Spinbox(
    root,
    from_=0,
    to=10,
    font=("Helvetica", 16),  # Fuente y tamaño
    bg="lightblue",         # Color de fondo
    fg="darkblue"           # Color del texto
)
spinbox.pack()

# Iniciar el bucle principal
root.mainloop()

Este código configura la fuente del Spinbox a Helvetica de 16 puntos, con un fondo azul claro y un texto azul oscuro.

Personalizar los botones del Spinbox


Modificar los botones de flecha del Spinbox es difícil, pero puedes ocultarlos y agregar botones personalizados.

def increment():
    value = int(spinbox.get())
    spinbox.delete(0, tk.END)
    spinbox.insert(0, value + 1)

def decrement():
    value = int(spinbox.get())
    spinbox.delete(0, tk.END)
    spinbox.insert(0, value - 1)

spinbox = tk.Spinbox(root, from_=0, to=10, state="readonly")  # Configurado como solo lectura
spinbox.pack()

button_up = tk.Button(root, text="▲", command=increment)
button_up.pack()

button_down = tk.Button(root, text="▼", command=decrement)
button_down.pack()

En este ejemplo, el Spinbox está configurado como “solo lectura”, y se usan botones personalizados para aumentar y disminuir el valor.

Ajustar el ancho y la colocación


Puedes ajustar el ancho del Spinbox utilizando la opción width, que se mide en número de caracteres.

spinbox = tk.Spinbox(root, from_=0, to=10, width=10)
spinbox.pack(padx=10, pady=10)  # Agregar márgenes alrededor del Spinbox

Además, puedes usar las opciones del método pack para colocar el Spinbox dentro de la ventana correctamente.

Cambiar el valor con la rueda del ratón


También puedes personalizar el Spinbox para que cambie su valor usando la rueda del ratón.

def scroll(event):
    value = int(spinbox.get())
    if event.delta > 0:  # Desplazamiento hacia arriba
        spinbox.delete(0, tk.END)
        spinbox.insert(0, value + 1)
    elif event.delta < 0:  # Desplazamiento hacia abajo
        spinbox.delete(0, tk.END)
        spinbox.insert(0, value - 1)

spinbox.bind("<MouseWheel>", scroll)

Este código cambia el valor del Spinbox cuando se desplaza la rueda del ratón hacia arriba o hacia abajo.

Agregar un tooltip


Puedes agregar un tooltip (mensaje de ayuda) al Spinbox para guiar a los usuarios.

def show_tooltip(event):
    tooltip_label.place(x=event.x_root, y=event.y_root)

def hide_tooltip(event):
    tooltip_label.place_forget()

tooltip_label = tk.Label(root, text="Seleccione un valor", bg="yellow", relief="solid")
spinbox.bind("<Enter>", show_tooltip)
spinbox.bind("<Leave>", hide_tooltip)

Este ejemplo muestra un tooltip cuando el cursor se encuentra sobre el Spinbox y lo oculta cuando el cursor sale de él.

Resumen

  • Cambiar fuentes y colores: Cambia el diseño usando las opciones font, bg, fg.
  • Botones personalizados: Oculta los botones de flecha y usa botones personalizados.
  • Ancho y colocación: Ajusta el diseño usando width y el método pack.
  • Interacciones adicionales: Agrega soporte para la rueda del ratón y tooltips.

La siguiente sección explica problemas comunes y errores que debes tener en cuenta al usar Spinbox.

Solución de problemas y precauciones


Al usar Spinbox, si no está configurado correctamente, pueden ocurrir comportamientos inesperados o errores. Esta sección explica los problemas comunes y cómo solucionarlos.

1. Los usuarios pueden ingresar valores fuera del rango


Aunque hayas configurado from_ y to, los usuarios aún pueden ingresar manualmente valores fuera del rango. Para evitarlo, usa validate y validatecommand para verificar el valor en tiempo real.

def validate_input(value):
    return value.isdigit() and 0 <= int(value) <= 10

vcmd = root.register(validate_input)

spinbox = tk.Spinbox(root, from_=0, to=10, validate="key", validatecommand=(vcmd, '%P'))
spinbox.pack()

Este código previene que los usuarios ingresen valores fuera del rango.

2. No se pueden manejar valores decimales


El Spinbox maneja valores enteros por defecto. Si necesitas manejar valores decimales, usa values o increment para configurar los pasos.

Soluciones:

  • Usar values para permitir valores decimales específicos.
  • Usar increment para configurar el tamaño de paso decimal.
spinbox = tk.Spinbox(root, from_=0, to=10, increment=0.1)
spinbox.pack()

3. No sabes cómo deshabilitar la entrada


Si deseas deshabilitar temporalmente el Spinbox, usa la opción state.

spinbox.config(state="disabled")  # Deshabilitar
spinbox.config(state="normal")    # Habilitar nuevamente

Esto deshabilita el Spinbox, impidiendo que el usuario pueda interactuar con él.

4. El valor predeterminado no está configurado


Si el valor inicial del Spinbox está vacío, el usuario puede confundirse. Usa el método insert para configurar un valor predeterminado.

spinbox.delete(0, tk.END)
spinbox.insert(0, 5)  # Establecer 5 como valor predeterminado

5. Los valores ingresados no se actualizan inmediatamente


Si los valores ingresados manualmente no se reflejan inmediatamente, usa command o eventos para capturar los cambios de entrada en tiempo real.

def on_change():
    value = spinbox.get()
    print(f"Valor cambiado: {value}")

spinbox = tk.Spinbox(root, from_=0, to=10, command=on_change)
spinbox.pack()

6. La rueda del ratón no funciona


En algunos casos, la rueda del ratón no está habilitada por defecto. Puedes agregar soporte para esto utilizando el evento <MouseWheel> y personalizar el comportamiento del Spinbox.

def scroll(event):
    value = int(spinbox.get())
    if event.delta > 0:  # Desplazamiento hacia arriba
        spinbox.delete(0, tk.END)
        spinbox.insert(0, value + 1)
    elif event.delta < 0:  # Desplazamiento hacia abajo
        spinbox.delete(0, tk.END)
        spinbox.insert(0, value - 1)

spinbox.bind("<MouseWheel>", scroll)

7. Quieres cambiar el rango dinámicamente


Para cambiar dinámicamente el rango de un Spinbox, utiliza el método config.

spinbox.config(from_=10, to=100)

Esto cambiará el rango del Spinbox dentro del programa.

8. Mostrar mensajes de error


Para mostrar un mensaje de error cuando el valor ingresado es incorrecto.

def validate_and_alert(value):
    if not value.isdigit() or not (0 <= int(value) <= 10):
        error_label.config(text="Por favor, ingrese un valor entre 0 y 10")
        return False
    error_label.config(text="")
    return True

vcmd = root.register(validate_and_alert)

spinbox = tk.Spinbox(root, from_=0, to=10, validate="key", validatecommand=(vcmd, '%P'))
spinbox.pack()

error_label = tk.Label(root, text="", fg="red")
error_label.pack()

Resumen

  • Usar validate para prevenir entradas fuera de rango.
  • Configurar las opciones adecuadas para manejar valores decimales o rangos dinámicos.
  • Mejorar la experiencia del usuario usando botones y eventos.
  • Mostrar mensajes de error cuando los usuarios ingresen datos incorrectos.

La siguiente sección resume cómo utilizar el Spinbox.

Resumen


Este artículo ha cubierto cómo usar el widget Spinbox de Python Tkinter para controlar la entrada numérica. Desde su uso básico hasta la validación de valores, manejo de números decimales, manipulación con botones y eventos, y personalización de su aspecto y funcionalidad.

Al usar Spinbox correctamente, puedes restringir fácilmente los valores que los usuarios pueden ingresar y construir formularios y interfaces más seguros y eficientes. Esto mejorará la fiabilidad y facilidad de uso de tus aplicaciones.

En tu próximo proyecto de desarrollo GUI, utiliza este artículo para crear interfaces de entrada más convenientes e intuitivas.

Índice