Search code examples
pythonpython-3.xtkintertextbox

How to validate text box inputs in real-time


Its an application which asks a math problem and user inputs answer in a textbox as integers, and a button submitbtn verifies if its right or wrong. I binded a keyboard key f to the function that runs on pressing button submitbtn, which works fine, but the key f gets added to the textbox after user's answer before it submits and gives it as a wrong answer.

Text Box

text_Input = StringVar
txtbox = Entry(font=('arial',20, BOLD), textvariable=text_Input)
txtbox.grid(columnspan = 2, row = 3, pady = 20)
txtbox.focus_set()

Submit Button

submitbtn = Button(text="Submit", padx=10, pady=10, command=lambda:submit(txtbox.get(), y))

Submit Function

def submit(z, y):
    global correct_answer, wrong_answer, submitbtn
    y=str(y)
    if z==y:
        correct_answer+=1
        lbl2.configure(text=correct_answer)
    else:
        wrong_answer+=1
        lbl4.configure(text=wrong_answer)
    submitbtn.config(state="disabled")

Binding

game.bind('f', lambda event: submit(txtbox.get(), y))
#"game" is the name of Tk()
#submit is the function linked to submitbtn
#This works well if I bind it to <Return> (Enter Key)

Actual Output:

5+8

User enters: 13

Presses 'f' to submit answer

Answer processed: 13f

  1. Is there a way to process textbox inputs in real-time to make sure every character entered is an integer? If user enters anything except 0-9, I want it to note nothing in the textbox.

  2. Also, I disable the submitbtn after it is pressed once, but pressing f repeatedly keep incrementing the correct_answer variable. Is there a way to bind the key to the submitbtn which in turn will call the function submit, instead of directly linking the key f to submit function?


Solution

  • For your first question, there are two ways to do it. Either you use the trace method on your StringVar, or use validcommand on your entry. You can read up the details on how to use both methods here and here

    import tkinter as tk
    
    root = tk.Tk()
    
    # Use trace method on your StringVar
    
    text_Input = tk.StringVar() # note that it is StringVar() with ()
    txtbox = tk.Entry(font="Arial 20 bold",textvariable=text_Input)
    txtbox.grid(columnspan = 2, row = 3, pady = 20)
    
    def trace_method(*args):
        if text_Input.get().isdigit():
            pass
        else:
            text_Input.set(text_Input.get()[:-1])
    
    text_Input.trace("w",trace_method)
    
    # Use validatecommand attribute of entry widget
    
    def onValidate(S):
        if S.isdigit():
            return True
        else:
            return False
    
    vcmd = (root.register(onValidate),"%S")
    
    txtbox2 = tk.Entry(font="Arial 20 bold",validate="key",validatecommand=vcmd)
    txtbox2.grid(columnspan = 2, row = 4, pady = 20)
    
    root.mainloop()
    

    For your second question, I can't fully understand what you are trying to achieve, but if the problem lies with the binding with key f, i suppose you can simply call game.unbind('f') in your submit function.