4

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

Tom Davis
  • 103
  • 1
  • 2
  • 9
  • Don't use `sleep()` in tkinter. use `after()` instead. the use of sleep will pause the entire tkinter instance and is probably not doing what you think its doing. – Mike - SMT Jun 27 '17 at 21:49
  • 2
    please create a [mcve]. As a general rule you should avoid your own game loop at all costs, since tkinter already has an infinite loop. We need to see how you've implemented your game loop. – Bryan Oakley Jun 27 '17 at 21:49
  • Hey, I've updated my question and removed many unimportant sections of my code. I just need my screen to stay how it is and nothing change after that button is created, and it to stay like that untill that button has been clicked, thankyou very much! – Tom Davis Jun 27 '17 at 22:11

2 Answers2

20

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.

Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
  • This sounds like exactly what im looking for however im getting a little error: I changed tk in your example to Tk, root and tk and each had errors, at the top of my program I have root = Tk(), why am i getting any of these errors and which one should I be using? var = Tk.IntVar(): AttributeError: type object 'Tk' has no attribute 'IntVar' ||| var = root.IntVar(): AttributeError: '_tkinter.tkapp' object has no attribute 'IntVar' ||| var = tk.IntVar(): NameError: name 'tk' is not defined – Tom Davis Jun 27 '17 at 22:28
  • I have fixed it by doing var = IntVar() Thank you very much Bryan I didnt know about this and it will be very useful with my game!! Thankyou very much!! – Tom Davis Jun 27 '17 at 22:43
1

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.

Mattchoo
  • 401
  • 4
  • 7
  • 1
    There is no difference between python 2 and python 3 in this regard. Your code didn't work because of this: http://stackoverflow.com/q/1101750/7432 – Bryan Oakley Jan 03 '22 at 22:07