Making Tkinter wait untill button is pressed

20,104

Solution 1

The simplest way to get tkinter to wait for some event is to call one of the "wait" functions, such as wait_variable, wait_window, or wait_visibility.

In your case you want to wait for a button click, so you can use wait_variable and then have the button set the variable. When you click the button the variable will be set, and when the variable is set the call to wait_variable will return.

For example:

import tkinter as tk
root = tk.Tk()
...
var = tk.IntVar()
button = tk.Button(root, text="Click Me", command=lambda: var.set(1))
button.place(relx=.5, rely=.5, anchor="c")

print("waiting...")
button.wait_variable(var)
print("done waiting.")

Note: you don't have to use IntVar -- any of the special Tkinter variables will do. Also, it doesn't matter what you set it to, the method will wait until it changes.

Solution 2

Just wanted to add a comment, but don't have enough reputation. I couldn't get the wait_variable(var) to work for me on the button. I had to use it on my frame. I'm guessing this is a change between Python 2 and 3.

Here is the error I got:

Traceback (most recent call last):

File "AutoPlotHydroData2.py", line 434, in btnOK.wait_variable(okVar) AttributeError: 'NoneType' object has no attribute 'wait_variable'

My working code reads:

    # Launch frame to collect needed input values
    myFrame = tk.Tk()
    myFrame.configure(background='lightblue')

    # Add some widgets

    # OK Button
    okVar = tk.IntVar()
    btnOK = tk.Button(myFrame, text="Submit", pady=5, font=("Arial Bold", 10),
        bg='lightgray', command=lambda: okVar.set(1)).grid(row=14, column=0)

    # Show frame
    myFrame.tkraise()

    # Wait for OK button to be pressed
    #btnOK.wait_variable(okVar) - this didn't work
    myFrame.wait_variable(okVar)

    # Close frame
    myFrame.destroy()

I have this code in a loop to process multiple files. Hope this helps someone.

Share:
20,104
Tom Davis
Author by

Tom Davis

Updated on March 15, 2020

Comments

  • Tom Davis
    Tom Davis about 4 years

    I have a game, When a button is created, I need my program to just show this screen untill they press 'Next Level' all of this code is in a while loop so in a large while loop controlling the game.

    ......

    if game.playerDistance >= game.lowerBound() and game.playerDistance <= game.upperBound():
            game.level += 1
    
            showLevelResults(game)
    
            #NextLevelButton
            btnNextLevel = Button(root,
                        #Random Config
                        command = nextLevel,
                        )
            btnNextLevel.place(x=1003, y=492, anchor=NW,  width=247, height=78)
    
            updateMainScreen()
    
            while nextLev == False:
                #What Do I put in here to force a wait
        else:
    

    ......

    nextLev = False
    def nextLevel():
        nextLev = True
    

    ...

    Currently this keeps it in the while loop and when the button is pressed nothing changes i have used time.sleep(1) to keep it waiting and also had it printing waiting for btn press, however this spams the console and when the button is pressed still doesnt change the screen.

    def showGameSurvival():
    
    game = gamemode_normal()
    
    while game.health != 0:
        game.next = False 
        clearScreen()
        changeBackground("Survival")
    
        #Placing Labels on the screen for game.....
    
        #... Health
        root.update()
    
        lblCountDownLeft = Label(root, bg="White", fg="Green", font=XXLARGE_BUTTON_FONT)
        lblCountDownLeft.place(x=169, y=350, anchor=CENTER)
        lblCountDownRight = Label(root, bg="White", fg="Green", font=XXLARGE_BUTTON_FONT)
        lblCountDownRight.place(x=1111, y=350, anchor=CENTER)
        #CountDown
        count = 7
        while count > 0:                
            lblCountDownLeft['text'] = count
            lblCountDownRight['text'] = count
            root.update()
            count -= 1
            time.sleep(1)
    
        lblCountDownLeft.destroy()
        lblCountDownRight.destroy()
        root.update()
        #Num on left x=169, right, x=1111 y=360
    
        game.measureDistance()
        if game.playerDistance >= game.lowerBound() and game.playerDistance <= game.upperBound():
            game.level += 1
            clearScreen()
            changeBackground("Survival")
            graphicalDisplay(game)
    
            #NextLevelButton
            btnNextLevel = Button(root,
                        bg= lbBlue,
                        fg="white",
                        text="Level" + str(game.level),
                        font=SMALL_BUTTON_FONT,
                        activebackground="white",
                        activeforeground= lbBlue,
                        command= lambda: nextLevel(game),
                        bd=0)
            btnNextLevel.place(x=1003, y=492, anchor=NW,  width=247, height=78)
            root.update()
            while game.next == False:
                print(game.next)
        else:
            game.health -= 1
    
        if game.allowance > 4:
            game.allowance = int(game.allowance*0.9)
    
    #when game is over delete the shit        
    if game.health == 0:
        del game
    

    The next button now calls this function: def nextLevel(game): game.next = True