Python Forum
Tkinter GUI Sleep alternative
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Tkinter GUI Sleep alternative
#1
Photo 
Hi,

I want to create a memory game. I need the game to pause for a while. I understand that sleep stops the whole program running which is no good. I have tried after but cannot get another function to create a user entry box to run from it.

1. The screen will load with instructions that says click the start button to begin the game.
2. Clicking start loads a picture with a label for its name (and supposedly starts a 5 second timer)
3. The image is supposed to go away and in its place is supposed to a user entry box where you can enter the name of the image you just saw.

I can get the picture and label to load and using after go away after 5 seconds. Any functions i add to this don't trigger.
I have just tried to fun a function off after (see function 'iamtrying' and it will print the string but wont destroy the image or create the entry box.
The bus image is attached to post.

Any help would be greatly received.
Thanks in advance


import tkinter as tk

window = tk.Tk()
window.title("Test Environment")
window.geometry("450x700")
window.configure(background="silver")
    
score = 0

def iamtrying():
    print("Hello")
    spot1.destroy
    spot1_label.destroy
    user_input=tk.Entry(window,width=50)
    user_input.place(x=85,y=600)

        
def startgame():
    global spot1
    bus_image = tk.PhotoImage(file="bus.png")
    spot1 = tk.Label(window,image=bus_image)
    spot1.image = bus_image
    spot1.place(x=90,y=130)
    spot1.after(5000,iamtrying)
    
    global spot1_label
    spot1_label=tk.Label(window,text="CAT",fg="black",bg="gold",font=("Arial",14,"bold"))
    spot1_label.place(x=90,y=240)
#    spot1_label.after(10000,spot1_label.destroy)
   


mylabel=tk.Label(window,text="click start, after 5 seconds images")
mylabel.place(x=90,y=400)

mylabe2=tk.Label(window,text="will disappear, name them in input box.")
mylabe2.place(x=90,y=430)

startbutt=tk.Button(window,text="START GAME",fg="black",bg="gold",width=15,font=("Arial",12,"bold"),command=startgame)
startbutt.place(x=140,y=550)


window.mainloop()

Attached Files

Thumbnail(s)
   
Reply
#2
The entry is created below the start button, the labels are not destroyed because destroy has not been called as there are no () at the end.
Change
def iamtrying():
    print("Hello")
    spot1.destroy
    spot1_label.destroy
    user_input=tk.Entry(window,width=50)
    user_input.place(x=85,y=600)
to
def iamtrying():
    print("Hello")
    spot1.destroy()
    spot1_label.destroy()
    user_input=tk.Entry(window,width=50)
    user_input.place(x=85,y=600)
Reply
#3
Brilliant - thank you very much!
Reply
#4
Another alternative. Uses forget_grid()
If you are going to be using several images extra code would be needed.

import tkinter as tk

class Window:
    ''' Class for creating the display window '''
    def __init__(self, parent):
        self.parent = parent
        self.parent.columnconfigure(0, weight=1)
        self.parent.rowconfigure(0, weight=1)

        container = tk.Frame(self.parent)
        container.grid(column=0, row=0, sticky='news')

        label = tk.Label(container)
        label.grid(column=0, row=0, sticky='new')
        label.configure(
            text = 'Click start, after 5 seconds images will disappear.\
 Name them in the input box.',
        justify = 'left',
        padx=10, pady=5,
        wraplength = 380,
        font = (None, 12, 'normal')
        )

        self.label = tk.Label(container, font=(None, 12, 'bold'))
        self.label.grid(column=0, row=1, sticky='news')

        img = tk.PhotoImage(file='bus.png')
        img.bak = img
        self.label.configure(image=img, compound='top', text='Cat')

        self.entry = tk.Entry(container)
        self.entry.grid(column=0, row=2, sticky='new', padx=10, pady=10)

        self.button = tk.Button(container, text='Start')
        self.button.grid(column=0, row=3, sticky='se', padx=20)


class Controller:
    ''' Controller class handles window operations '''
    def __init__(self, window):
        self.window = window

        # Create count variable
        self.counter = 5

        # Hide our grid for label and entry
        self.window.label.grid_forget()
        self.window.entry.grid_forget()

        # Button command
        self.window.button.configure(command=self.show_pic)

    def show_pic(self):
        ''' Method for swapping grid labels '''
        self.window.label.grid(column=0, row=1, sticky='news')

        # Call after to do the countdown
        countme = self.window.parent.after(1000, self.show_pic)

        # Each call will subtract 1 from counter
        self.counter -= 1

        # When the counter reaches 0, swap label grids
        if self.counter <= 0:
            self.window.label.grid_forget()
            self.window.entry.grid(column=0, row=2, sticky='new', padx=10, pady=10)

            # Stop the .after call
            self.window.parent.after_cancel(countme)



if __name__ == '__main__':
    root = tk.Tk()
    root.geometry('400x300+200+200')
    controller = Controller(Window(root))
    root.mainloop()
I welcome all feedback.
The only dumb question, is one that doesn't get asked.
My Github
How to post code using bbtags
Download my project scripts


Reply
#5
(Oct-16-2024, 07:20 PM)the_muffin_man Wrote: 2. Clicking start loads a picture with a label for its name (and supposedly starts a 5 second timer)

This is a fairly common use. Use tkinter's after() to run the timer, which does not stop the entry or any other part of the program. This program is a test program that I wrote some time ago, that demonstrates
    import tkinter as tk

    class TimedInput():
       def __init__(self):
          self.top = tk.Tk()
          self.top.title("Test of After")
          self.top.geometry("200x200+10+10")

          tk.Label(self.top, text="you have 20 seconds",
                   bg="lightblue").grid(row=0, column=0)
          self.lab=tk.Label(self.top, width=6, bg="orange")
          self.lab.grid(row=1, column=0)
          tk.Label(self.top, text="-"*30
                  ).grid(row=2, column=0)
          self.ctr = 20

          self.entry_1 = tk.Entry(self.top, width=15)
          self.entry_1.grid(row=3, column=0)
          self.entry_1.focus_set()

          tk.Button(self.top, bg="lightyellow", text="Get Entry", 
                    command=self.entry_get, activebackground="lightblue",
                    ).grid(row=4, column=0, sticky="nsew")
          tk.Button(self.top, bg="red", text="Exit", 
                    command=self.top.quit, activebackground="white",
                    ).grid(row=5, column=0, sticky="nsew")

          self.top.after(100, self.increment_counter)
          self.top.mainloop()

       def entry_get(self):
           print("Entry is", self.entry_1.get())
           ## cancel current timer
           self.top.after_cancel(self.after_id)

           ## start timer and get next entry 
           self.entry_1.delete(0, tk.END)
           self.ctr=20
           self.top.after(100, self.increment_counter)

       def increment_counter(self):
          self.ctr -= 1
          self.lab.config(text=self.ctr)

          if self.ctr > 0:
              self.after_id=self.top.after(1000, self.increment_counter)
          else:
              print("\n timing loop ended")
              self.top.quit()

    ##====================================================================
    if __name__ == '__main__':
       CT=TimedInput() 
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  [Tkinter] Is there a way to sleep without stopping user input? GalaxyCoyote 2 2,689 Oct-23-2019, 06:23 PM
Last Post: Denni
  [Tkinter] sleep(n) not working inside tkinter mainloop roger31415 2 6,263 Jul-14-2019, 06:57 PM
Last Post: wuf

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020