Como controlar a entrada de números usando o widget Spinbox em Python

O Tkinter é a biblioteca padrão de GUI do Python e oferece vários widgets. Entre eles, o Spinbox é um widget muito útil quando é necessário restringir a entrada de números ou textos. Este artigo explica amplamente desde o uso básico do Spinbox até exemplos avançados e como controlar a entrada de dados, ajudando a criar aplicativos mais seguros e eficientes ao controlar os valores que o usuário pode inserir.

Índice

Uso básico do Spinbox


O Spinbox é um dos widgets fornecidos pelo Tkinter, permitindo que o usuário selecione ou insira um valor dentro de um intervalo especificado. Veja um exemplo básico de uso abaixo.

Criando um Spinbox


O Spinbox é criado utilizando a classe Spinbox. Abaixo está um exemplo de código para exibir um Spinbox simples.

import tkinter as tk

# Criação da janela Tkinter
root = tk.Tk()
root.title("Exemplo Básico de Spinbox")

# Criação do Spinbox
spinbox = tk.Spinbox(root, from_=0, to=10)
spinbox.pack()

# Início do loop principal
root.mainloop()

Explicação do código

  1. Opções from_ e to
  • from_ define o valor mínimo do Spinbox.
  • to define o valor máximo do Spinbox.
    Neste exemplo, os valores que podem ser selecionados variam de 0 a 10.
  1. Método pack()
  • Usado para posicionar o Spinbox na janela.

Verificação do funcionamento


Ao executar o código acima, um Spinbox será exibido, permitindo que o usuário selecione um valor entre 0 e 10 usando os botões de seta.

Na próxima seção, explicaremos como ajustar ainda mais o intervalo de valores que podem ser inseridos no Spinbox.

Como definir um intervalo de números


O Spinbox permite que você defina um intervalo de valores que o usuário pode inserir. Configurando adequadamente esse intervalo, você pode evitar a inserção de valores inesperados e garantir uma entrada de dados mais segura e eficiente.

Definindo um intervalo com from_ e to


Usando as opções from_ e to no Spinbox, é possível definir os valores mínimo e máximo que podem ser inseridos.

import tkinter as tk

# Criação da janela Tkinter
root = tk.Tk()
root.title("Definição de Intervalo de Números")

# Criação do Spinbox (intervalo de 1 a 100)
spinbox = tk.Spinbox(root, from_=1, to=100)
spinbox.pack()

# Início do loop principal
root.mainloop()

Neste exemplo, apenas valores de 1 a 100 podem ser inseridos. Caso o usuário tente inserir um valor fora deste intervalo, o Spinbox não aceitará.

Definindo o tamanho do passo


A opção increment permite definir o valor pelo qual o número muda cada vez que o usuário interage com o Spinbox (o tamanho do passo).

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

Com essa configuração, os valores no intervalo de 0 a 50 aumentam ou diminuem de 5 em 5 (0, 5, 10, …).

Especificando valores de uma lista


Se você deseja permitir apenas certos valores, pode usar a opção values para especificar uma lista de opções permitidas.

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

Neste exemplo, apenas os valores 10, 20, 30, 40 e 50 podem ser selecionados.

Alterando dinamicamente o intervalo


O intervalo de valores do Spinbox também pode ser alterado dinamicamente no código. Veja o exemplo abaixo de como alterar o intervalo em tempo real.

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

button = tk.Button(root, text="Alterar Intervalo", command=update_range)
button.pack()

Usando o método config, é possível alterar facilmente as propriedades do Spinbox.

Na próxima seção, abordaremos como validar os valores inseridos no Spinbox em tempo real.

Validando a entrada com funções de callback


Validar os valores do Spinbox em tempo real ajuda a prevenir entradas inválidas e permite criar aplicações mais robustas e seguras. O Tkinter oferece a possibilidade de usar funções de callback para realizar essa validação.

Registrando funções de callback


Para registrar uma função de callback, que será chamada sempre que o valor do Spinbox for alterado, usamos a opção command.

import tkinter as tk

# Função de callback
def on_value_change():
    value = spinbox.get()
    print(f"Valor atual: {value}")

# Criação da janela Tkinter
root = tk.Tk()
root.title("Exemplo de Função de Callback")

# Criação do Spinbox
spinbox = tk.Spinbox(root, from_=0, to=10, command=on_value_change)
spinbox.pack()

# Início do loop principal
root.mainloop()

Esse código chama a função on_value_change sempre que o valor do Spinbox é alterado, exibindo o valor atual na tela.

Adicionando validação de valores


Para validar que o valor inserido atende a um critério específico, basta analisar o valor obtido e realizar a verificação desejada.

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

Registrando essa função no command, a cada mudança no valor do Spinbox, a condição é verificada e o resultado é impresso.

Usando validate e validatecommand


Para validações mais rigorosas, você pode usar as opções validate e validatecommand.

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

# Registrando o comando de validação do Tkinter
vcmd = root.register(validate_input)

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

Pontos principais do código

  • validate="key": Realiza a validação durante a entrada de dados do teclado.
  • validatecommand: Especifica a função usada para validar os valores.
  • '%P': Passa o valor atual da entrada para a função de validação.

Este exemplo verifica se o valor inserido é numérico e se está dentro do intervalo de 0 a 10, bloqueando entradas inválidas.

Exibindo mensagens de erro


A seguir, mostramos como exibir uma mensagem de erro caso o valor inserido não atenda às condições especificadas.

def validate_and_alert(value):
    if not value.isdigit() or not (0 <= int(value) <= 10):
        error_label.config(text="O valor deve estar entre 0 e 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()

Com isso, qualquer valor fora do intervalo será bloqueado e o erro será imediatamente notificado ao usuário.

Na próxima seção, veremos como restringir a entrada de números decimais ou valores específicos.

Restrições de entrada para números decimais ou valores específicos


O Spinbox lida com valores inteiros por padrão, mas você pode configurá-lo para aceitar números decimais ou restringir a entrada a valores específicos, proporcionando controle flexível sobre a entrada de dados.

Permitindo números decimais


Para permitir que o Spinbox aceite números decimais, você pode usar a opção values para especificar uma lista de valores permitidos.

import tkinter as tk

# Criação da janela Tkinter
root = tk.Tk()
root.title("Controle de Entrada de Números Decimais")

# Criando lista de números decimais
decimal_values = [x / 10 for x in range(0, 101)]  # 0.0 a 10.0

# Criação do Spinbox
spinbox = tk.Spinbox(root, values=decimal_values)
spinbox.pack()

# Início do loop principal
root.mainloop()

Neste exemplo, o Spinbox aceita valores decimais (0.0, 0.1, 0.2, …, 10.0). Ao passar uma lista para a opção values, você pode permitir que o Spinbox aceite valores além de números inteiros.

Permitindo números decimais com valor de passo


Usando as opções from_, to e increment, você também pode especificar o tamanho do passo para trabalhar com números decimais.

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

Este exemplo permite valores no intervalo de 0.0 a 10.0 com um incremento de 0.1.

Permitindo valores específicos


Se você deseja permitir apenas valores específicos, pode usar a opção values para especificar quais valores são permitidos.

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

Este exemplo permite que apenas os valores 1.5, 2.5, 3.5 e 4.5 sejam selecionados.

Restrição flexível de entrada combinando validação


Se você deseja restringir a entrada a um número específico de casas decimais ou apenas aceitar valores que atendam a uma condição específica, você pode combinar a opção validate e validatecommand.

def validate_float(value):
    try:
        # Verificando se a entrada é um decimal e está no intervalo permitido
        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()

Esse código permite que apenas valores decimais válidos entre 0.0 e 10.0 sejam inseridos no Spinbox.

Forçando um formato de entrada


Se você quiser forçar o formato de entrada, pode usar uma função de callback para formatar a entrada conforme necessário.

def format_input():
    value = spinbox.get()
    try:
        formatted_value = f"{float(value):.2f}"  # Formatar para 2 casas decimais
        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()

Esse código aplica o formato de 2 casas decimais à entrada do Spinbox sempre que seu valor for alterado.

Na próxima seção, veremos como manipular o valor do Spinbox com botões.

Manipulando o valor do Spinbox com botões


Alterar dinamicamente o valor do Spinbox usando botões pode ser útil para melhorar a experiência do usuário e criar cenários específicos em que a entrada do usuário não seja a única forma de modificar o valor.

Obtendo o valor do Spinbox


Para obter o valor atual do Spinbox, use o método get.

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

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

Este código obtém o valor do Spinbox e o exibe no console ao clicar no botão “Obter valor”.

Definindo o valor do Spinbox


O valor do Spinbox pode ser alterado usando os métodos delete e insert.

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

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

Este código define o valor do Spinbox para 5 ao clicar no botão “Definir valor”.

Criando botões de incremento e decremento


Para criar botões que aumentam ou diminuem o valor do Spinbox, basta obter o valor atual, fazer o cálculo necessário e definir o novo valor.

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="Aumentar", command=increment)
button_increment.pack()

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

Este código cria dois botões, um para aumentar o valor e outro para diminuir.

Implementação com restrição de intervalo


Se desejar garantir que o valor do Spinbox não ultrapasse o intervalo especificado, você pode adicionar lógica para verificar os limites e impedir a alteração fora desses limites.

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

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

button_increment_safe = tk.Button(root, text="Aumentar com segurança", command=increment_safe)
button_increment_safe.pack()

button_decrement_safe = tk.Button(root, text="Diminuir com segurança", command=decrement_safe)
button_decrement_safe.pack()

Este exemplo impede que o valor do Spinbox seja alterado fora do intervalo definido.

Exemplo avançado: Resetando para o valor padrão


Você pode adicionar uma funcionalidade para resetar o Spinbox a um valor inicial sob certas condições.

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

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

Este código reseta o valor do Spinbox para 0 quando o botão “Resetar” é clicado.

Na próxima seção, veremos como aplicar o Spinbox em um formulário.

Exemplo prático: Aplicando o Spinbox em formulários


O Spinbox pode ser útil para criar formulários que exigem entradas numéricas ou seleções específicas de opções. Aqui estão alguns exemplos de como usar o Spinbox para coletar entradas em um formulário.

Exemplo: Formulário de entrada de idade


Vamos criar um formulário para que o usuário insira sua idade usando um Spinbox.

import tkinter as tk

# Criação da janela Tkinter
root = tk.Tk()
root.title("Formulário de Idade")

# Criando o Spinbox para idade
tk.Label(root, text="Por favor, insira sua idade:").pack()
age_spinbox = tk.Spinbox(root, from_=0, to=120)
age_spinbox.pack()

# Função de envio
def submit_form():
    age = age_spinbox.get()
    result_label.config(text=f"Idade inserida: {age}")

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

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

# Início do loop principal
root.mainloop()

Este código cria um Spinbox para entrada da idade, e ao clicar no botão “Enviar”, a idade inserida é exibida abaixo do formulário.

Exemplo: Aplicação em um formulário de reservas


Você pode usar o Spinbox para definir a quantidade de pessoas ou o horário de uma reserva, como no exemplo abaixo.

# Criação da janela Tkinter
root = tk.Tk()
root.title("Formulário de Reserva")

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

# Spinbox para o horário da reserva
tk.Label(root, text="Horário da reserva:").pack()
time_spinbox = tk.Spinbox(root, values=("12:00", "13:00", "14:00", "15:00", "16:00"))
time_spinbox.pack()

# Função de envio da reserva
def submit_reservation():
    guests = guest_spinbox.get()
    time = time_spinbox.get()
    result_label.config(text=f"Número de pessoas: {guests} pessoas, Horário: {time}")

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

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

# Início do loop principal
root.mainloop()

Esse formulário permite que o usuário selecione o número de pessoas e o horário da reserva com o Spinbox.

Exemplo: Usando múltiplos Spinboxes


Você pode usar múltiplos Spinboxes para formular entradas mais complexas, como data e hora.

# Spinboxes para data
tk.Label(root, text="Ano:").pack()
year_spinbox = tk.Spinbox(root, from_=2000, to=2100)
year_spinbox.pack()

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

tk.Label(root, text="Dia:").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"Data inserida: {year} ano(s) {month} mês(es) {day} dia(s)")

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

Este exemplo usa múltiplos Spinboxes para selecionar ano, mês e dia, criando um formulário de data.

Melhorando o design do formulário


Você pode melhorar a usabilidade do formulário usando os seguintes pontos:

  • Posicionamento das labels: Organize as labels de forma clara para que o usuário entenda o que deve preencher.
  • Definir valores padrões: Defina valores padrão para reduzir as opções que o usuário precisa selecionar.
  • Exibição de mensagens de erro: Adicione mensagens de erro quando o usuário inserir dados inválidos.

Na próxima seção, abordaremos como personalizar ainda mais o Spinbox.

Personalizando o Spinbox


O Spinbox pode ser personalizado para se ajustar melhor ao design da sua aplicação. Vamos ver como alterar sua aparência e comportamento.

Alterando fontes e cores


Você pode alterar a fonte, a cor de fundo e a cor do texto do Spinbox usando as opções font, bg (cor de fundo) e fg (cor do texto).

import tkinter as tk

# Criação da janela Tkinter
root = tk.Tk()
root.title("Personalização do Spinbox")

# Criando Spinbox com fonte e cores alteradas
spinbox = tk.Spinbox(
    root,
    from_=0,
    to=10,
    font=("Helvetica", 16),  # Fonte e tamanho
    bg="lightblue",         # Cor de fundo
    fg="darkblue"           # Cor do texto
)
spinbox.pack()

# Início do loop principal
root.mainloop()

Este código altera o tamanho da fonte para 16 pontos, a fonte para Helvetica, a cor de fundo para azul claro e a cor do texto para azul escuro.

Personalizando os botões do Spinbox


Embora seja difícil alterar diretamente os botões de seta do Spinbox, você pode ocultá-los e adicionar seus próprios botões 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")  # Definido como somente leitura
spinbox.pack()

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

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

Este exemplo remove os botões de seta padrão e adiciona dois botões personalizados para aumentar e diminuir o valor.

Ajustando a largura e o posicionamento


A largura do Spinbox pode ser ajustada usando a opção width, que define a largura em termos de caracteres.

spinbox = tk.Spinbox(root, from_=0, to=10, width=10)
spinbox.pack(padx=10, pady=10)  # Adicionando espaço ao redor do Spinbox

Você também pode usar o método pack para ajustar o posicionamento do Spinbox dentro da janela.

Alterando o valor com a roda do mouse


O valor do Spinbox também pode ser alterado usando a roda do mouse.

def scroll(event):
    value = int(spinbox.get())
    if event.delta > 0:  # Rola para cima
        spinbox.delete(0, tk.END)
        spinbox.insert(0, value + 1)
    elif event.delta < 0:  # Rola para baixo
        spinbox.delete(0, tk.END)
        spinbox.insert(0, value - 1)

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

Este código permite que o valor do Spinbox seja alterado usando a roda do mouse.

Adicionando Tooltips


Você pode adicionar tooltips (dicas) ao Spinbox para ajudar os usuários a entender como usá-lo.

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="Selecione um valor", bg="yellow", relief="solid")
spinbox.bind("<Enter>", show_tooltip)
spinbox.bind("<Leave>", hide_tooltip)

Com esse código, um tooltip é exibido sempre que o usuário passa o cursor sobre o Spinbox.

Resumo

  • Alterando fontes e cores: Modifique o estilo do Spinbox usando font, bg e fg.
  • Botões personalizados: Oculte os botões padrão e use seus próprios botões.
  • Ajuste de largura e posicionamento: Use a opção width ou pack para organizar o layout.
  • Interatividade adicional: Implemente interações com a roda do mouse ou tooltips.

Na próxima seção, discutiremos problemas comuns ao usar o Spinbox e como resolvê-los.

Resolução de Problemas e Considerações


Embora o Spinbox seja muito útil, alguns problemas podem surgir se ele não for configurado corretamente. Abaixo, abordamos alguns problemas comuns e suas soluções.

1. O usuário consegue inserir valores fora do intervalo


Mesmo que você defina o intervalo usando from_ e to, o usuário ainda pode inserir manualmente um valor fora desse intervalo. Para evitar isso, você deve usar a opção validate e validatecommand para validar a entrada em tempo 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()

Esse código impede que o usuário insira valores fora do intervalo no Spinbox.

2. Não aceitando números decimais


Por padrão, o Spinbox aceita apenas números inteiros. Para permitir números decimais, use a opção values ou increment.

Soluções:

  • Use values para permitir números decimais específicos.
  • Use increment para definir um passo decimal.
spinbox = tk.Spinbox(root, from_=0, to=10, increment=0.1)
spinbox.pack()

3. Não consegue desabilitar a entrada


Para desabilitar temporariamente o Spinbox, use a opção state.

spinbox.config(state="disabled")  # Desabilita
spinbox.config(state="normal")    # Reabilita

Isso impede que o usuário interaja com o Spinbox até que seja reabilitado.

4. Valor padrão não configurado


Se o valor inicial do Spinbox estiver vazio, o usuário pode se confundir. Use o método insert para definir um valor padrão.

spinbox.delete(0, tk.END)
spinbox.insert(0, 5)  # Definindo o valor padrão como 5

5. Valores inseridos manualmente não são refletidos imediatamente


Se os valores inseridos manualmente não são refletidos imediatamente, use a opção command ou um evento para capturar a entrada em tempo real.

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

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

6. A roda do mouse não funciona


Por padrão, o Spinbox não responde à roda do mouse. Use o evento <MouseWheel> para adicionar essa funcionalidade.

def scroll(event):
    value = int(spinbox.get())
    if event.delta > 0:  # Para cima
        spinbox.delete(0, tk.END)
        spinbox.insert(0, value + 1)
    elif event.delta < 0:  # Para baixo
        spinbox.delete(0, tk.END)
        spinbox.insert(0, value - 1)

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

7. Como alterar o intervalo dinamicamente


Para alterar o intervalo de valores do Spinbox dinamicamente, use o método config.

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

Isso permite alterar os limites do intervalo em tempo real.

8. Exibindo mensagens de erro


Para exibir uma mensagem de erro quando o usuário inserir um valor inválido, use uma função de validação.

def validate_and_alert(value):
    if not value.isdigit() or not (0 <= int(value) <= 10):
        error_label.config(text="O valor deve estar entre 0 e 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()

Resumo

  • Use validate para evitar valores fora do intervalo.
  • Defina valores decimais ou use o increment para manipular o passo.
  • Use botões e eventos para melhorar a interatividade.
  • Exiba mensagens de erro quando valores inválidos forem inseridos.

Na próxima seção, concluiremos com uma visão geral de como usar o Spinbox de forma eficaz.

Conclusão


Este artigo explorou diversos métodos para controlar a entrada de números usando o widget Spinbox do Tkinter em Python. Desde o uso básico até a validação de entradas, a manipulação de valores decimais e a personalização da aparência, cobrimos uma variedade de técnicas que podem ser aplicadas para melhorar a usabilidade de seus aplicativos.

Usando o Spinbox corretamente, você pode criar interfaces mais seguras e eficientes, controlando facilmente os valores inseridos pelos usuários. Aplique as dicas e exemplos deste artigo para construir formulários e interfaces de usuário mais intuitivos e funcionais em suas aplicações Python.

Continue explorando o Tkinter e crie interfaces gráficas cada vez mais sofisticadas e amigáveis.

Índice