How do I make time.sleep() work with tkinter? - python

I'm trying to show a sequence of numbers on the screen at regular intervals.
I'm new to python so it may be something obvious but I have tried .after and pygame.time.wait, but neither worked.
this is the code:
from tkinter import*
from random import *
import time
my_list = []
def Create_NUM(event):
x = 0
for x in range(level + 2):
button1.destroy()
num = randint(1, 100)
my_list.append(num)
Label(root, text=num,fg="red").pack()
one.pack()
time.sleep(2)
root=Tk()
num = 0
level = 1
bottomFrame = Frame(root)
bottomFrame.pack(side=BOTTOM)
button1 = Button(bottomFrame, text="Click to start game",fg="red")
button1.bind("<Button-1>", Create_NUM)
button1.pack()
root.mainloop()

I assume you want to show new number in place of old number, not below it.
import tkinter as tk
import random
def start():
# hide button
button.pack_forget()
# run `add_number` first time
add_number(level+2)
def add_number(x):
num = random.randint(1, 100)
my_list.append(num)
label['text'] = num
if x > 0:
# repeat after 2000ms (2s)
root.after(2000, add_number, x-1)
else:
# show button again after the end
button.pack()
# --- main ---
my_list = []
level = 1
root = tk.Tk()
label = tk.Label(root)
label.pack()
button = tk.Button(root, text="Click to start game", command=start)
button.pack()
root.mainloop()

Just use this simple command in your function root.update()

Related

Why isn't the variable from my spinbox returning? (python, tkinter)

import tkinter as tk
from tkinter import *
root = tk.Tk()
root.grid()
numEntry = tk.StringVar()
printButton = tk.IntVar()
# Check if the number submitted is zero.
def checkZero():
num = numEntry.get()
print("Number Inputted =",num)
if num == 0:
print("Yes")
elif num != 0:
print("No")
numEntry = Spinbox(root, from_= 0, to = 100000, wrap=True)
printButton = Button(root, text="Print", command=checkZero)
numEntry.grid(column=0, row=0)
printButton.grid(column=1, row=0)
root.mainloop()
What am I doing wrong here?
It's as if the .get() method isn't being called at all.
Very new to programming and python, so there's a solid chance I'm missing something small.
I found out what the issue was!
I didn't make sure that my numEntry turned out to be an integer.
import tkinter as tk
from tkinter import *
root = tk.Tk()
root.grid()
numEntry = tk.StringVar()
printButton = tk.IntVar()
# Check if the number submitted is zero.
def checkZero():
num = int(numEntry.get())
print("Number Inputted =",num)
if num == 0:
print("Yes")
elif num != 0:
print("No")
numEntry = Spinbox(root, from_= 0, to = 100000, wrap=True)
printButton = Button(root, text="Print", command=checkZero)
numEntry.grid(column=0, row=0)
printButton.grid(column=1, row=0)
root.mainloop()

Python: stop one incidence of recursive function and run another without resuming the first

I am trying to make a game using a countdown timer for 60s.
My issue is that as the countdown timer is recursive, it keeps running until t == 0 when it runs the endgame() function.
if you pass the level, the initial countdown timer will still end after 60s which in turn will end the game. I need a way to run the next level without the initial countdown ending and ending the game.
I have tried using if True statements at the start of the function which only paused the loop until the next instance of the function started.
code:
from tkinter import *
import ctypes
from scrambld_back import *
from tkinter import font
import time
from nltk.corpus import words
user32 = ctypes.windll.user32
screensize = [user32.GetSystemMetrics(0), user32.GetSystemMetrics(1)]
root = Tk()
root.geometry(f'500x500+{screensize[1]-250}+100')
root.title('Scrambld')
root.configure(bg='white')
over = Tk()
over.geometry(f'500x500+{screensize[1]-250}+100')
root.title('Scrambld')
root.configure(bg='white')
over.iconify()
gamefont = font.Font(family='impact', size=30)
levelfont = font.Font(family='impact', size=20)
level = 0
Label(over, text='GAME OVER', font=gamefont)
Label(over, text=f'Level {level}', font=levelfont)
def endgame():
over = Toplevel(root)
over.geometry(f'500x500+{screensize[1]-250}+100')
Label(over, text='GAME OVER', font=gamefont).place(x=250, y=215, anchor='center')
Label(over, text=f'Level {level}', font=levelfont).place(x=250, y=285, anchor='center')
def play(level):
t = 15
gamewords = []
for x in words.words():
if len(x) == level+3:
gamewords.append(x)
word = gamewords[random.randint(0, len(gamewords))]
gameplay = generate(list(word))
Label(root, text=f'Level {level}', font=levelfont, bg='white').place(x=250, y=70, anchor='center')
Label(root, text=gameplay, font=gamefont, bg='white', width=100).place(x=250, y=140, anchor='center')
guess = Entry(root, font=levelfont, bg='white')
guess.place(x=250, y=360, anchor='center')
guess.bind('<Return>', lambda event, word=word: compare(event, word))
def compare(event, word):
if word.upper() == guess.get().upper():
play(level+1)
else:
pass
submit = Button(root, text='SUBMIT', font=levelfont, bg='white', width=21, command=lambda: compare(None, word))
submit.place(x=250, y=420, anchor='center')
timer = StringVar()
Label(root, textvariable=timer, font=levelfont, bg='white', width=8).place(x=250, y=250, anchor='center')
def countdown(t, lev):
print(lev, level)
print(t)
t=int(t)-1
if t < 10:
t=f'0{t}'
timer.set(f'00:{t}')
root.update()
if int(t) < 1 and lev == level:
endgame()
else:
root.after(1000, lambda: countdown(t, lev))
countdown(t, 1)
play(1)

Unable to label text using config in tkinter

So, I have been trying to create a simple stopwatch in tkinter in which I created a loop to update text to new time i.e., the next second in timer label as I click button_1. I tried to do this with StringVar() as well as .config method but none of them are updating the text in label. The code is below
from datetime import *
from time import *
init_time = datetime(100, 1, 1, 0, 0, 0)
running = True
def clock():
while running == True:
sleep(1)
global init_time
a = init_time.strftime("%H:%M:%S")
mtime.set(a)
init_time = init_time + timedelta(seconds=1)
def stop():
global running
running = False
main = Tk()
main.geometry("500x200")
mtime = StringVar()
timer = Label(main, textvariable = mtime, width=30, bg="black", fg="white", font=(25))
timer.place(x=90, y=20)
button_1 = Button(main, text = "Start", command = clock()).place(x=170, y=120)
button = Button(main, text = "Stop", command = stop).place(x=250, y=120)
main.mainloop()
I even tried to convert the init_time to a string because I thought maybe the updates of text work only for strings. The initial GUI window shows but as I click button_1 it doesn't work.
You did common mistake, look at these two lines
button_1 = Button(main, text = "Start", command = clock()).place(x=170, y=120)
button = Button(main, text = "Stop", command = stop).place(x=250, y=120)
Note that you have clock() and stop. First is function invocation, second is function. You should provide function as command. Replace clock() using clock.
Also if you are interested in executing function every n miliseconds, please take look at .after, consider following simple timer
import tkinter as tk
elapsed = 0
def update_timer():
global elapsed
elapsed += 1
timer['text'] = str(elapsed)
root.after(1000, update_timer) # 1000 ms = 1 second
root = tk.Tk()
timer = tk.Label(root, text="0")
btn = tk.Button(root, text="Go", command=update_timer)
timer.pack()
btn.pack()
root.mainloop()

how to cancel the after method for an off delay timer in tkinter using python 3.8

I have a off delay program in which when I select the input checkbutton, the output is 1. When I deselect the input checkbutton, the output goes back to 0 after a timer (set up in a scale). For that I use the after method. That part works. My problem is that I want to reset the timer if the checkbutton is selected again before the output went to 0; but once the checkbutton is selected the first time, the after method get triggered and it doesn't stop. I'm trying to use after_cancel, but I can't get it to work. Any solution?
from tkinter import *
root = Tk()
t1= IntVar()
out = Label(root, text="0")
remain_time = IntVar()
grab_time = 1000
def start_timer(set_time):
global grab_time
grab_time = int(set_time) * 1000
def play():
if t1.get() == 1:
button1.configure(bg='red')
out.configure(bg="red", text="1")
else:
button1.configure(bg='green')
def result():
out.configure(bg="green", text="0")
out.after(grab_time,result)
button1 = Checkbutton(root,variable=t1, textvariable=t1, command=play)
time = Scale(root, from_=1, to=10, command=start_timer)
button1.pack()
time.pack()
out.pack()
root.mainloop()
Expected: when press the checkbutton before the output went to 0, reset the counter.
So you could use the .after_cencel when the value of checkbutton is 1:
from tkinter import *
root = Tk()
t1= IntVar()
out = Label(root, text="0")
remain_time = IntVar()
grab_time = 1000
def start_timer(set_time):
global grab_time
grab_time = int(set_time) * 1000
def play():
if t1.get() == 1:
button1.configure(bg='red')
out.configure(bg="red", text="1")
try: # when the first time you start the counter, root.counter didn't exist, use a try..except to catch it.
root.after_cancel(root.counter)
except :
pass
else:
button1.configure(bg='green')
def result():
out.configure(bg="green", text="0")
root.counter = out.after(grab_time,result)
button1 = Checkbutton(root,variable=t1, textvariable=t1, command=play)
time = Scale(root, from_=1, to=10, command=start_timer)
button1.pack()
time.pack()
out.pack()
root.mainloop()

How can I update a text box 'live' in tkinter?

I would like to ask how would I go about maybe creating a 'LIVE' text box in python? This program is a simulator for a vending machine (code below). I want there to be a text box showing a live credit update How do you do that in tkinter?
For Example: Say there is a box for credit with 0 inside it in the middle of the window. When the 10p button is pressed the box for credit should change from '0' to '0.10'.
Is it possible to do thit in tkinter and python 3.3.2?
Thank you in advance!
import sys
import tkinter as tk
credit = 0
choice = 0
credit1 = 0
coins = 0
prices = [200,150,160,50,90]
item = 0
i = 0
temp=0
n=0
choice1 = 0
choice2 = 0
credit1 = 0
coins = 0
prices = [200,150,160,50,90]
item = 0
i = 0
temp=0
n=0
choice1 = 0
choice2 = 0
def addTENp():
global credit
credit+=0.10
def addTWENTYp():
global credit
credit+=0.20
def addFIFTYp():
global credit
credit+=0.50
def addPOUND():
global credit
credit+=1.00
def insert():
insert = Tk()
insert.geometry("480x360")
iLabel = Label(insert, text="Enter coins.[Press Buttons]").grid(row=1, column=1)
tenbutton = Button(insert, text="10p", command = addTENp).grid(row=2, column=1)
twentybutton = Button(insert, text="20p", command = addTWENTYp).grid(row=3, column=1)
fiftybutton = Button(insert, text="50p", command = addFIFTYp).grid(row=4, column=1)
poundbutton = Button(insert, text="£1", command = addPOUND).grid(row=5, column=1)
insert()
Sure you can! Just add another label to the frame, and update the text attribute whenever one of your add functions is called. Also, you can simplify that code, using one add function for all the different amounts.
def main():
frame = Tk()
frame.geometry("480x360")
Label(frame, text="Enter coins.[Press Buttons]").grid(row=1, column=1)
display = Label(frame, text="") # we need this Label as a variable!
display.grid(row=2, column=1)
def add(amount):
global credit
credit += amount
display.configure(text="%.2f" % credit)
Button(frame, text="10p", command=lambda: add(.1)).grid(row=3, column=1)
Button(frame, text="20p", command=lambda: add(.2)).grid(row=4, column=1)
Button(frame, text="50p", command=lambda: add(.5)).grid(row=5, column=1)
Button(frame, text="P1", command=lambda: add(1.)).grid(row=6, column=1)
frame.mainloop()
main()
Some more points:
note that you define many of your variables twice
you should not give a variable the same name as a function, as this will shadow the function
probably just a copy paste error, but you forgot to call mainloop and your tkinter import is inconsistent with the way you use the classes (without tk prefix)
you can do the layout right after creating the GUI elements, but note that in this case not the GUI element will be bound to the variable, but the result of the layouting function, which is None
Borrowing a framework from tobias_k's excellent answer, I would recommend you use a DoubleVar instead.
from tkinter import ttk
import tkinter as tk
def main():
frame = Tk()
frame.geometry("480x360")
credit = tk.DoubleVar(frame, value=0)
# credit = tk.StringVar(frame, value="0")
ttk.Label(frame, textvariable = credit).pack()
def add_credit(amt):
global credit
credit.set(credit.get() + amt)
# new_credit = str(int(credit.get().replace(".",""))+amt)
# credit.set(new_credit[:-2]+"."+new_credit[-2:])
ttk.Button(frame, text="10p", command = lambda: add_credit(0.1)).pack()
# ttk.Button(frame, text="10p", command = lambda: add_credit(10)).pack()
ttk.Button(frame, text="20p", command = lambda: add_credit(0.2)).pack()
# ttk.Button(frame, text="20p", command = lambda: add_credit(20)).pack()
ttk.Button(frame, text="50p", command = lambda: add_credit(0.5)).pack()
# ttk.Button(frame, text="50p", command = lambda: add_credit(50)).pack()
ttk.Button(frame, text="P1", command = lambda: add_credit(1.0)).pack()
# ttk.Button(frame, text="P1", command = lambda: add_credit(100)).pack()
frame.mainloop()
The comments in that code is an alternate implementation that will work better, if only just. This will guarantee you won't have any strange floating-point errors in your code.

Categories