timer function with global variable not counting down - python

so I am made a function that counts down, I have it count down from number n minus 1, it works but if I add a global variable (I named it flag, if flag == True then I want it to count down. if flag == False the I want timer to stop, I need that this variable to be global b/c I have another button that changes flag to False if pressed called pause. however my function does not display 5 , 4, 3, 2,1 every second. it just displays 5 now, when I add the global variables. and it only happens if I added global variables. please tell me what need to change. I am open to the idea of changing the way, I pause and play this function, if there is a different way to do so.
flag = True
holder_for_time = 6
# timer for next ball
def update_timer_countdown(n):
global flag
if flag == True and n != "1":
n = int(n)
n -= 1
n = str(n)
timer.config(
text="Next draw in:" + n + "s", padx=5, pady=45, font=("Helvetica", 17)
)
return timer.after(1000, update_timer_countdown, 6) # this step does not come through
elif flag == True and n == "1":
return update_timer_countdown(6)
elif flag == False:
global holder_for_time
holder_for_time = n
timer = Label(root, text="Next draw in:" + "s", padx=5, pady=45, font=("Helvetica", 17))
timer.grid(row=1, column=1, columnspan=2, rowspan=5, sticky="nsew")
update_timer_countdown(6)

I have edit few lines of code, and now it works how you want
here is the code
from tkinter import *
flag = True
holder_for_time = 6
n = 6
# timer for next ball
def update_timer_countdown():
global flag, n
if flag:
if n != 0:
n -= 1
timer.config(
text=f"Next draw in: {n}s", padx=5, pady=45, font=("Helvetica", 17)
)
return timer.after(1000, update_timer_countdown) # this step does not come through
else:
global holder_for_time
holder_for_time = n
def _command():
global flag
flag = not flag
if flag:
pause['text'] = "pause"
else:
pause['text'] = "resume"
update_timer_countdown()
def restart_command():
global flag, n
flag = True
n = 6
update_timer_countdown()
root = Tk()
timer = Label(root, text="Next draw in:", padx=5, pady=45, font=("Helvetica", 17))
timer.grid(row=1, column=1, columnspan=2, rowspan=5, sticky="nsew")
update_timer_countdown()
pause = Button(root, text="pause", font=("Helvetica", 10), command=_command)
pause.grid(row=0, column=0)
restart = Button(root, text="Restart", font=("Helvetica", 10), command=restart_command)
restart.grid(row=0, column=1)
root.mainloop()

Related

Why does my python code not continue execution once my function "executelogin()" has been executed?

I am encountering a problem where my code does NOT continue execution of the rest of the program once my called function, completes execution.
Here is the function that is being called:
def executelogin():
global initiate_game_window
global checker
counter = 1
while counter < 4:
global login_tk, game, us1_entry, us2_entry, us1_pwd_entry, us2_pwd_entry
login_tk = Tk(screenName="Login - RollADie")
titlelabel = Label(text="Welcome to rollaDie", font=('Open Sans', '20'))
titlelabel.grid(column=0, row=0, sticky=NSEW)
sublabel = Label(text="Login Below: ", font=('Open Sans', '10'))
sublabel.grid(column=0, row=1, sticky=NSEW)
us1_label = Label(text="User 1:")
us1_label.grid(row=2, column=0, sticky=NSEW)
us1_entry = Entry(width=10, textvariable=us1_uname)
us1_entry.grid(row=3, column=0, sticky=NSEW)
us1_pwd_label = Label(text="Password:")
us1_pwd_label.grid(row=4, column=0, sticky=NSEW)
us1_pwd_entry = Entry(width=10, show="*", textvariable=us1_pwrd)
us1_pwd_entry.grid(row=5, column=0, sticky=NSEW)
us2_label = Label( text="User 2:")
us2_label.grid(row=6, column=0, sticky=NSEW)
us2_entry = Entry(width=10, textvariable=us2_uname)
us2_entry.grid(row=7, column=0, sticky=NSEW)
us2_pwd_label = Label(text="Password:")
us2_pwd_label.grid(row=8, column=0, sticky=NSEW)
us2_pwd_entry = Entry(width=10, show="*", textvariable=us2_pwrd)
us2_pwd_entry.grid(row=9, column=0, sticky=NSEW)
def get_credentials():
global us1_entry, us2_entry, us1_pwd_entry, us2_pwd_entry, top_login
us1_uname = us1_entry.get()
us1_pwrd = us1_pwd_entry.get()
us2_uname = us2_entry.get()
us2_pwrd = us2_pwd_entry.get()
print(us1_uname, us1_pwrd, us2_uname, us2_pwrd)
global credentials
credentials = [us1_uname, us1_pwrd, us2_uname, us2_pwrd]
top_login.destroy()
global top_login
top_login = tk.Toplevel()
top_login.geometry('1x1+0+0')
top_login.overrideredirect(True)
submit_button = Button(text="Submit", command=get_credentials)
submit_button.grid(row=10, column=0, sticky=NSEW)
top_login.wait_window(top_login)
us1_auth = False
us2_auth = False
if login(credentials[0], credentials[1]) == True:
us1_auth = True
else:
pass
if login(credentials[2], credentials[3]) == True:
us2_auth = True
else:
pass
if us1_auth == True:
if us2_auth == True:
print("Auth POS")
messagebox.showinfo(message="AUTHORISED")
login_tk.destroy()
break
else:
print("User 2 AUTH NEG")
messagebox.showinfo(message="User 2 Denied")
counter += 1
if counter > 3:
messagebox.showinfo(message="MAX ATTEMPTS")
quit()
continue
else:
print("AUTH USER 1 NEG")
messagebox.showinfo(message="USER 1 NOT AUTHORISED")
counter += 1
if counter > 3:
messagebox.showinfo(message="MAX ATTEMPTS")
quit()
continue
login_tk.mainloop()
I am not sure why this is not continuing on with the rest of the code as expected.
I'd appreciate any help.
For further reference, there is another Tk object in this file, which is initiated later down.
Thanks
şehzade Muhammad Amen Ehsan
Edit:
Below this function is the following code:
top = None
top_roll2 = None
faces = {'1':'\u2680', '2':'\u2681', '3':'\u2682', '4':'\u2683', '5':'\u2684', '6':'\u2685'}
root = Tk(className='RollADice', screenName='RollADice')
title = Label(text='RollADice by. Amen', font=('Open Sans', '20')).grid(row=0, column=0, sticky=NSEW)
round_teller = Label(text='Currently: Round {0}'.format(roundnum))
round_teller.grid(row=1, column=0, sticky=NSEW)
dicelabel = Label(root)
my 2 cents: you are creating a Tk instance within that function, and hence you have an infinite loop that wont finish until you exit from it; that is, until you exit from the login_tk mainloop.

Tkinter while loop guess game

# Tkinter guessing game
from tkinter import *
import random
window = Tk()
# Bot Generator
bot = random.randint(1, 20+1)
print(bot)
def submit():
tries = 5
while tries >= 0:
e1 = (int(guessE.get()))
if e1 == bot:
print("You win")
break
elif e1 != bot:
print("Try again")
tries -= 1
break
def clear():
guessE.delete(0, "end")
# Guess Label
guessL = Label(window, text="Guess a number (between 1 and 20}")
guessL.place(x=75, y=50)
# Guess Entry
guessE = Entry(window, width=25, bg="lightgrey")
guessE.place(x=95, y= 80)
# Submit Button
submitBtn = Button(window, width=10, height=2, text="Submit", command=submit)
submitBtn.place(x=85, y=115)
# Clear Button
clearBtn = Button(window, width=10, height=2, text="Clear", command=clear)
clearBtn.place(x=175, y=115)
window.geometry("350x350")
window.resizable(0, 0)
window.attributes("-topmost", True)
window.mainloop()
I am trying to create a guessing game with Tkinter, I have created all the entries and labels, the clear button is working. I am struggling with creating a while loop, I need the program to stop accepting submitted entries once 5 tries have been used. Any ideas on how I can solve this?
Like already mentioned by #Paul Rooney, i also think that a while loop is a bad design for this. However, here is a working example with a global variable and some minor changes (disabling entry and button when 0 tries are reached):
# Tkinter guessing game
from tkinter import *
import random
window = Tk()
# Bot Generator
bot = random.randint(1, 20+1)
print(bot)
# define outside of function to not overwrite each time
tries = 5
def submit():
global tries # to make tries a global variable
while tries > 0: # this matches your tries amount correctly
e1 = (int(guessE.get()))
if e1 == bot:
print("You win")
break
elif e1 != bot:
print("Try again")
tries -= 1
break
# print status, disable the widgets
if tries == 0:
print("No more tries left")
guessE.configure(state="disabled")
submitBtn.configure(state="disabled")
def clear():
guessE.delete(0, "end")
# Guess Label
guessL = Label(window, text="Guess a number (between 1 and 20}")
guessL.place(x=75, y=50)
# Guess Entry
guessE = Entry(window, width=25, bg="lightgrey")
guessE.place(x=95, y= 80)
# Submit Button
submitBtn = Button(window, width=10, height=2, text="Submit", command=submit)
submitBtn.place(x=85, y=115)
# Clear Button
clearBtn = Button(window, width=10, height=2, text="Clear", command=clear)
clearBtn.place(x=175, y=115)
window.geometry("350x350")
window.resizable(0, 0)
window.attributes("-topmost", True)
window.mainloop()

Get input in Python tkinter Entry when Button pressed

I am trying to make a 'guess the number' game with Pyhon tkinter but so far I have not been able to retrieve the input from the user.
How can I get the input in entry when b1 is pressed?
I also want to display a lower or higher message as a clue to the player but I am not sure if what I have is right:
import time
import random
import decimal
import tkinter as tk
root = tk.Tk()
randomnum = float(decimal.Decimal(random.randrange(100,10000))/100)
guess = 0
def get(entry):
guess = entry.get()
return guess
def main():
b1 = tk.Button(root, text="Guess", command=get)
entry = tk.Entry()
b1.grid(column=1, row=0)
entry.grid(column=0, row=0)
root.mainloop()
print(guess)
if guess < randomnum:
l2 = tk.Label(root, text="Higher!")
l2.grid(column=0, row=2)
elif guess > randomnum:
l3 = tk.Label(root, text="Lower!")
l3.grid(column=0, row=2)
while guess != randomnum:
main()
l4 = tk.Label(root, text="Well guessed")
time.sleep(10)
You could define get inside main, so that you can access the entry widget you created beforehand, like this:
entry = tk.Entry()
def get():
guess = entry.get()
return guess # Replace this with the actual processing.
b1 = tk.Button(root, text="Guess", command=get)
You've assembled random lines of code out of order. For example, the root.mainloop() should only be called once after setting up the code but you're calling it in the middle of main() such that anything after won't execute until Tk is torn down. And the while guess != randomnum: loop has no place in event-driven code. And this, whatever it is, really should be preceded by a comment:
randomnum = float(decimal.Decimal(random.randrange(100,10000))/100)
Let's take a simpler, cleaner approach. Rather than holding onto pointers to the the various widgets, let's use their textvariable and command properties to run the show and ignore the widgets once setup. We'll use StringVar and IntVar to handle input and output. And instead of using sleep() which throws off our events, we'll use the after() feature:
import tkinter as tk
from random import randint
def get():
number = guess.get()
if number < random_number:
hint.set("Higher!")
root.after(1000, clear_hint)
elif number > random_number:
hint.set("Lower!")
root.after(1000, clear_hint)
else:
hint.set("Well guessed!")
root.after(5000, setup)
def setup():
global random_number
random_number = randint(1, 100)
guess.set(0)
hint.set("Start Guessing!")
root.after(2000, clear_hint)
def clear_hint():
hint.set("")
root = tk.Tk()
hint = tk.StringVar()
guess = tk.IntVar()
random_number = 0
tk.Entry(textvariable=guess).grid(column=0, row=0)
tk.Button(root, text="Guess", command=get).grid(column=1, row=0)
tk.Label(root, textvariable=hint).grid(column=0, row=1)
setup()
root.mainloop()
Here is a tkinter version on the number guessing game.
while or after are not used!
Program checks for illegal input (empty str or words) and reports error message. It also keeps track of the number of tries required to guess the number and reports success with a big red banner.
I've given more meaningful names to widgets and used pack manager instead of grid.
You can use the button to enter your guess or simply press Return key.
import time
import random
import tkinter as tk
root = tk.Tk()
root.title( "The Number Guessing Game" )
count = guess = 0
label = tk.Label(root, text = "The Number Guessing Game", font = "Helvetica 20 italic")
label.pack(fill = tk.BOTH, expand = True)
def pick_number():
global randomnum
label.config( text = "I am tkinking of a Number", fg = "black" )
randomnum = random.choice( range( 10000 ) )/100
entry.focus_force()
def main_game(guess):
global count
count = count + 1
entry.delete("0", "end")
if guess < randomnum:
label[ "text" ] = "Higher!"
elif guess > randomnum:
label[ "text" ] = "Lower!"
else:
label.config( text = f"CORRECT! You got it in {count} tries", fg = "red" )
root.update()
time.sleep( 4 )
pick_number()
count = 0
def get( ev = None ):
guess = entry.get()
if len( guess ) > 0 and guess.lower() == guess.upper():
guess = float( guess )
main_game( guess )
else:
label[ "text" ] = "MUST be A NUMBER"
entry.delete("0", "end")
entry = tk.Entry(root, font = "Helvetica 15 normal")
entry.pack(fill = tk.BOTH, expand = True)
entry.bind("<Return>", get)
b1 = tk.Button(root, text = "Guess", command = get)
b1.pack(fill = tk.BOTH, expand = True)
pick_number()
root.geometry( "470x110" )
root.minsize( 470, 110 )
root.mainloop()
Correct way to write guess number.
I write a small script for number guessing game in Python in
get_number() function.
Used one widget to update Label instead of duplicating.
I added some extra for number of turns that you entered.
Code modified:
import time
import random
import decimal
import tkinter as tk
root = tk.Tk()
randomnum = float(decimal.Decimal(random.randrange(100,10000))/100)
print(randomnum)
WIN = False
GUESS = 0
TURNS = 0
Vars = tk.StringVar(root)
def get_number():
global TURNS
while WIN == False:
Your_guess = entry.get()
if randomnum == float(Your_guess):
guess_message = f"You won!"
l3.configure(text=guess_message)
number_of_turns = f"Number of turns you have used: {TURNS}"
l4.configure(text=number_of_turns)
l4.grid(column=0, row=3, columnspan=3, pady=5)
WIN == True
break
else:
if randomnum > float(Your_guess):
guess_message = f"Your Guess was low, Please enter a higher number"
else:
guess_message = f"your guess was high, please enter a lower number"
l3.configure(text=guess_message)
l3.grid(column=0, row=2, columnspan=3, pady=5)
TURNS +=1
return Your_guess
label = tk.Label(root, text="The Number Guessing Game", font="Helvetica 12 italic")
label.grid(column=0, row=0, columnspan=3, sticky='we')
l2 = tk.Label(root, text='Enter a number between 1 and 100',
fg='white', bg='blue')
l2.grid(row=1, column=0, sticky='we')
entry = tk.Entry(root, width=10, textvariable=Vars)
entry.grid(column=1, row=1, padx=5,sticky='w')
b1 = tk.Button(root, text="Guess", command=get_number)
b1.grid(column=1, row=1, sticky='e', padx=75)
l3 = tk.Label(root, width=40, fg='white', bg='red' )
l4 = tk.Label(root, width=40, fg='white', bg='black' )
root.mainloop()
while guess:
time.sleep(10)
Output for enter floating numbers:
Output after the guess was high:
Output after the guess was low:
Output You won and number of turns:

tkinter: pull down menu un-clickable

I am creating a tkinter window that updates a matrix multiplication result every second. I wish to use pull down menus to create options for users.
However, since the entire window is re-drawn every second for the matrix update, the pull down menus are re-initialized every second, rendering them pretty much useless.
I am wondering if there is any way around this problem.
Thanks in advance.
from tkinter import *
import time
import sys
def update(a):
root.title("Matrix Multiplication")
menu = Menu(root)
root.config(menu= menu)
subMenu = Menu(menu)
menu.add_cascade(label="Options", menu=subMenu)
subMenu.add_command(label="Opt1...",command=win2)
exitMenu = Menu(menu)
menu.add_cascade(label="Exit", menu=exitMenu)
exitMenu.add_command(label="Exit",command=root.destroy)
X0 = [[8,7,3],[4 ,5,6],[7 ,8,9]]
Y0 = [[5,8,1,2],[6,7,3,0],[4,5,9,1]]
result0 = [[0,0,0,0],[0,0,0,0],[0,0,0,0]]
if a == 0:
cpfg = ["magenta", "blue", "green", "purple"]
cpbg = ["white", "white", "white", "white"]
button1 = Button(root, text="Button-1", fg=cpfg[0], bg=cpbg[0])
button2 = Button(root, text="Button-2", fg=cpfg[1], bg=cpbg[1])
button3 = Button(root, text="Button-3", fg=cpfg[2], bg=cpbg[2])
button4 = Button(root, text="Button-4", fg=cpfg[3], bg=cpbg[3])
button1.grid(row=0, column=0)
button2.grid(row=0, column=1)
button3.grid(row=0, column=2)
button4.grid(row=0, column=3)
a = 1
elif a >= 1 and a <= 3:
for b in range(len(X0)):
for c in range(len(X0[0])):
X0[b][c] *= a
a += 1
else:
for b in range(len(X0)):
for c in range(len(X0[0])):
X0[b][c] *= a
a = 1
for i in range(len(X0)):
for j in range(len(Y0[0])):
for k in range(len(Y0)):
result0[i][j] += X0[i][k] * Y0[k][j]
agrp = LabelFrame(root, text="Process-0", padx=5, pady=5)
agrp.grid(row=2, column=1)
for r in range(3):
for c in range(4):
Label(agrp, text=result0[r][c],
borderwidth=4 ).grid(row=r,column=c)
root.after(1000, lambda x = a: update(x))
def win2():
board = Toplevel()
board.title("Message")
S = Scrollbar(board)
T = Text(board, height=4, width=50)
T.pack()
S.pack(side=RIGHT, fill=Y)
T.pack(side=LEFT, fill=Y)
S.config(command=T.yview)
T.config(yscrollcommand=S.set)
quote = """Yep, this is text"""
T.insert(END, quote)
root = Tk()
a=0
update(a)
root.mainloop()
The update method should only calculate and display changes.
def update(a):
if a == 0:
a = 1
elif a >= 1 and a <= 3:
for b in range(len(X0)):
for c in range(len(X0[0])):
X0[b][c] *= a
a += 1
else:
for b in range(len(X0)):
for c in range(len(X0[0])):
X0[b][c] *= a
a = 1
for i in range(len(X0)):
for j in range(len(Y0[0])):
for k in range(len(Y0)):
result0[i][j] += X0[i][k] * Y0[k][j]
for r in range(3):
for c in range(4):
Label(agrp, text=result0[r][c],
borderwidth=4 ).grid(row=r,column=c)
root.after(1000, lambda x = a: update(x))

Tkinter wit while loop (python 3)

First I created a window with some buttons and I defined their commands. It all works fine until I add the while loop to check if any button was pressed and then move to the next step. But then the window doesn't show up and the loop is running forever. I would also like to know if there is a better alternative to my code.
from tkinter import *
Round = 0
def blackC():
global Round
print ('0')
x = 0
Round += 1
def brownC():
global Round
print ('1')
x = 1
Round +=1
def redC():
global Round
print ('2')
x = 2
Round += 2
def win():
window = Tk()
window.geometry ('500x500')
window.title('HELLO')
blackB = Button(text = 'BLACK', command=blackC, width=7, height=3, bd=5)
blackB.place(x=1, y=1)
brownB = Button(text = 'BROWN', command=brownC, width=7, height=3, bd=5)
brownB.place(x=86, y=1)
redB = Button(text = 'RED', command=redC, width=7, height=3, bd=5)
redB.place(x=172, y=1)
window.mainloop()
while (Round == 0):
win()
while (Round < 3):
if (Round == 1):
y = x * 10
print ('y')
elif (Round == 2):
y += x
print ('y')
I don't know what exactly you mean by moving to the next step, but you definitely misunderstand how tkninter works. You are missing the parenthesis in the mainloop window.mainloop().
And you don't want to call it in the cycle, because mainloop is a function which is cycle. So you just run it once a time a then it runs infinitely. So your code have to just run once a time function win().
from tkinter import *
Round=0
def button(type):
global Round
print (str(type))
x = type
Round += type
def win():
window = Tk()
window.geometry ('500x500')
window.title('HELLO')
blackB = Button(text = 'BLACK', command=lambda: button(0), width=7, height=3, bd=5)
blackB.place(x=1, y=1)
brownB = Button(text = 'BROWN', command=lambda: button(1), width=7, height=3, bd=5)
brownB.place(x=86, y=1)
redB = Button(text = 'RED', command=lambda: button(2), width=7, height=3, bd=5)
redB.place(x=172, y=1)
window.mainloop
win()
You have asked for better code, so I have rewritten your buttons func for a one, which just takes an parametr of type and call it as a lambda function (take a look: http://www.diveintopython.net/power_of_introspection/lambda_functions.html.
For a larger projects it is better to have tkinter window as a class, but in this is it enough.

Categories

Resources