Tkinter SimpleDialog Timeout

1.1k Views Asked by At

I have a program that requires input to a module while it is running, so I am implementing a simple Dialog box to get input from the user to use in my Tkinter program. But I also need it to timeout when running the module as a console program, to pass over it or timeout after so many seconds when the user is not interacting with it. And not to have it just sit there and wait forever until the user interacts with it. How do I terminate the window after a timeout? Here is what I have now ...


def loginTimeout(timeout=300):
    root = tkinter.Tk()
    root.withdraw()
    start_time = time.time()
    input1 = simpledialog.askinteger('Sample','Enter a Number')
    while True:
        if msvcrt.kbhit():
            chr = msvcrt.getche()
            if ord(chr) == 13: # enter_key
                break
            elif ord(chr) >= 32: #space_char
                input1 += chr
        if len(input1) == 0 and (time.time() - start_time) > timeout:
            break

    print('')  # needed to move to next line
    if len(input1) > 0:
        return input1
    else:
        return input1
1

There are 1 best solutions below

6
On

Not entirely sure what the question is, but you could use the tkinter after() method in a similar way to this:

import tkinter as tk

root = tk.Tk()
root.geometry('100x100')

def get_entry() -> str:
    """Gets and returns the entry input, and closes the tkinter window."""
    entry = entry_var.get()
    root.destroy() # Edit: Changed from root.quit()
    return entry

# Your input box
entry_var = tk.StringVar()
tk.Entry(root, textvariable=entry_var).pack()

# A button, or could be an event binding that triggers get_entry()
tk.Button(root, text='Enter/Confirm', command=get_entry).pack()

# This would be the 'timeout'
root.after(5000, get_entry)

root.mainloop()

So, if the User enters something they can hit confirm or launch an event binded to the entry, or after the delay the program runs get_entry anyway. Maybe this will give you an idea, you can also check out the other widget methods: https://effbot.org/tkinterbook/widget.htm

EDIT: I'm not sure how this is arranged in your program, but root.mainloop() blocks, so once it's running, code after it won't run until the mainloop() exits. If you're function is part of a toplevel() window, you could use wait_window() to prevent the function from advancing until your timeout destroys the toplevel window or the function is called before by the User. The example, although probably not the best solution, would be:

def loginTimeout(timeout_ms: int=5000):
    root = tk.Tk()
    root.geometry('200x50')

    # function to get input and change the function variable
    input_ = ''
    def get_input():
        nonlocal input_
        input_ = entry_var.get()
        root.destroy()

    # build the widgets
    entry_var = tk.StringVar()
    tk.Entry(root, textvariable=entry_var).pack(side='left')
    tk.Button(root, text='Confirm', command=get_input).pack(side='right')

    # timeout
    root.after(timeout_ms, get_input)

    # mainloop
    root.mainloop()

    # won't get here until root is destroyed
    return input_

print(loginTimeout())