Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Making Tkinter wait untill button is pressed

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

like image 974
Tom Davis Avatar asked Dec 02 '22 11:12

Tom Davis


2 Answers

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.

like image 144
Bryan Oakley Avatar answered Dec 05 '22 01:12

Bryan Oakley


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.

like image 43
Mattchoo Avatar answered Dec 05 '22 02:12

Mattchoo