I am making a random number guessing game with GUI (Tkinter) and this comes up RuntimeError: threads can only be started once. I'm trying to kill the thread but I can't find any way. Here's the code:
def main(c):
global max_num, number, guess_num, enter, l1, t1
if c <= 5:
messagebox.showerror(title='Import error', message='Please add a bigger number than 5')
max_num.delete(0, END)
else:
number = random.randrange(1, c+1)
print(number)
t1 = threading.Thread(target=lambda: process(int(guess_num.get())))
l1 = Label(root, text='Whats the number?')
guess_num = Entry(root, bd=3)
enter = Button(root, text='Enter', command=t1.start)
l1.grid(row=2)
guess_num.grid(row=3)
enter.grid(row=3, column=1)
def process(answer):
global number
if number == answer:
result = Label(root, text='Correct Answer!')
result.grid(row=4)
guess_num.destroy()
enter.destroy()
l1.destroy()
else:
if answer > number:
wrong_result = Label(root, text='Wrong Answer! Your answer is bigger than the random number', fg='red')
elif answer < number:
wrong_result = Label(root, text='Wrong Answer! Your answer is smaller than the random number', fg='red')
wrong_result.grid(row=4)
time.sleep(3)
wrong_result.destroy()
In the first function (main) is where I call the Thread and in the second function (process) is where I want to kill the Thread.
The error is trying to tell you that passing command=t1.start will result in calling start() on the same t1 instance every time the button is pressed. In Python, you cannot call thread.start() multiple times on the same thread instance. Change the following lines:
...
print(number)
t1 = threading.Thread(target=lambda: process(int(guess_num.get())))
l1 = Label(root, text='Whats the number?')
guess_num = Entry(root, bd=3)
enter = Button(root, text='Enter', command=t1.start)
...
To
...
print(number)
def process_in_thread():
t1 = threading.Thread(target=lambda: process(int(guess_num.get())))
t1.start()
l1 = Label(root, text='Whats the number?')
guess_num = Entry(root, bd=3)
enter = Button(root, text='Enter', command=process_in_thread)
...
Related
# 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()
So I'm making a game where there is a random number and you have to guess the number while all displayed on an interface. The code was working without the interface (this is the "guess" function) but as soon as I tried to move it into the function when the button is pressed, the game always freezes.
Could someone help me find the problem?
from tkinter import *
import random
import time
root = Tk()
root.title("Mack's totally advanced Number Guesser!")
root.geometry('404x300')
root.resizable(False,False)
root.configure(bg='black')
fontA = 'BigNoodleTitling'
fontSizeA = 20
num = random.randint(1, 100)
# The issue is below
def guess():
correctGuess = False
while (correctGuess == False):
guess = guessEnt.get()
guess = int(guess)
if (guess == num):
correctGuess = True
welcomeLbl.config(text="Correct! Congratulations...")
elif (guess > num):
welcomeLbl.config(text='Err, TOO HIGH. Try Again.')
elif (guess < num):
welcomeLbl.config(text='Errrrrr, TOO LOW. Try Again.')
def start():
instrButton.grid_forget()
startButton.grid_forget()
welcomeLbl.config(text="Guess The Number! (1-100)")
welcomeLbl.grid(pady=30)
guessEnt.grid(row=3, column=0)
guessButton.grid(row=4, column=0, pady=20)
def instructions():
instrButton.grid_forget()
startButton.grid_forget()
welcomeLbl.config(text="So you need instructions ay?")
welcomeLbl.update()
time.sleep(3)
welcomeLbl.config(text="Well, it's quite simple")
welcomeLbl.update()
time.sleep(2)
welcomeLbl.config(text="Just guess the number!")
welcomeLbl.update()
time.sleep(3)
welcomeLbl.config(text="How you say?")
welcomeLbl.update()
time.sleep(2)
welcomeLbl.config(text="Type your guess into the box!")
welcomeLbl.update()
time.sleep(3)
welcomeLbl.config(text="Welcome Random Person")
instrButton.grid(row=3,column=0, sticky=N)
startButton.grid(row=4,column=0, columnspan=1, sticky=E+W, pady=25)
titleLbl = Label(root)
titleLbl['borderwidth'] = (2)
titleLbl['relief'] = ('solid')
titleLbl['text'] = ("Mack's totally advanced Number Guessing Game!")
titleLbl['font'] = (fontA, fontSizeA)
titleLbl.grid(row=0, column=0)
welcomeLbl = Label(root, fg='white', bg='black')
welcomeLbl['text'] = ("Welcome Random Person")
welcomeLbl['font'] = (fontA, 30)
welcomeLbl.grid(row=2, column=0, pady=20)
instrButton = Button(root, command=instructions)
instrButton['text'] = ("Instructions")
instrButton['font'] = (fontA, fontSizeA)
instrButton.grid(row=3,column=0, sticky=N)
startButton = Button(root, fg='red', command=start)
startButton['text'] = ("Start")
startButton['font'] = (fontA, 40)
startButton.grid(row=4,column=0, columnspan=1, sticky=E+W, pady=25)
guessEnt = Entry(root)
guessEnt['font'] = (fontA, fontSizeA)
guessButton = Button(root, command=guess)
guessButton['text'] = ("Guess")
guessButton['font'] = (fontA, 20)
root.mainloop()
Thanks,
Mack.
Remove while (correctGuess == False):. If the answer is incorrect, it will drop into an infinite loop since correctGuess doesn't change in the loop -- it's always False. You can add print(1) in the loop -- you'll see that it can't exit. Remove that line and it should be fine.
I am trying to make a guess game program where you have to guess a number between 0-100 on a GUI using Tkinter, and it also counts your amount of attempts but I get this error on line 25:
'<' is not supported between instances of str and int.
What can I do to solve this issue? This code would work on a command line but not when I have attempted to translate it into a GUI. I am also not sure if the code even works.
My updated code so far is:
import random
from tkinter import *
#need to count how many attempts you made
window = Tk()
window.title("Number guessing game")
window.geometry('350x200')
lbl = Label(window, text="Enter a number here from 1-100: ")
lbl.grid(column=0,row=0)
guess_var = IntVar(window)
txt = Entry(window, textvariable=guess_var)
txt= Entry(window, width=10)
txt.grid(column=1,row=0)
numguess = 0
secret_num = random.randint(1, 100)
def clicked():
if guess < 0:
lbl2.configure(text ="Please enter a sensible number.")
if guess > 100:
lbl2.configure(text ="Please enter a sensible number.")
if guess == secret_num:
lbl2.configure(text ="You guessed correctly.")
lbl3.confgure(text=numguess)
elif guess < secret_num:
numguess = numguess + 1
lbl2.configure(text ="higher!")
lbl = Label(window, text="Enter a number here from 1-100: ")
else:
numguess = numguess + 1
lbl2.configure(text ="lower!")
lbl = Label(window, text="Enter a number here form 1-100")
lbl2 = Label(window,text = " ")
lbl2.grid(column=1, row=2)
lbl3 = Label(window,text = " ")
lbl3.grid(column=1, row=3)
btn = Button(window, text="Enter", command=clicked)
guess = int(txt.get())
btn.grid(column=3, row=0)
window.mainloop()
guess = txt.get()
returns a string value. To be able to perform comparisons with integers, you need to convert guess from a string to an integer, i.e.:
guess = int(txt.get())
To be safe, you may want to handle the case where the user inputs something which cannot be converted to a integer; how to do this depends on the design of your problem - you should consider validating the user input.
One way to do this could be by using IntVar, e.g.:
guess_var = IntVar(window)
txt = Entry(window, textvariable=guess_var)
txt.grid(column=1,row=0)
numguess = 0
secret_num = random.randint(1, 100)
guess = guess_var.get()
Note that if you want to use the numguess global variable inside your clicked function, you need to declare global numguess in your function definition, e.g.:
def clicked():
global numguess
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:
What is wrong with this program? Every time I run it the first math problem is show before I push start. Also the answer is always the first math problem, it never changes. Also there should not be a math problem above the timer. Thanks, Scott
from Tkinter import*
import time
import tkMessageBox
import random
def Questions():
number1 = random.randrange(1,25)
number2 = random.randrange(1,50)
answer = number1 + number2
prompt = ("Add " + str(number1) + " and " + str(number2))
label1 = Label(root, text=prompt, width=len(prompt), bg='yellow')
label1.pack()
return answer
def start():
global count_flag
Questions()
count_flag = True
count = 0.0
while True:
if count_flag == False:
break
# put the count value into the label
label['text'] = str(count)
# wait for 0.1 seconds
time.sleep(0.1)
# needed with time.sleep()
root.update()
# increase count
count += 0.1
def Submit(answer, entryWidget):
""" Display the Entry text value. """
global count_flag
count_flag = False
print answer
if entryWidget.get().strip() == "":
tkMessageBox.showerror("Tkinter Entry Widget", "Please enter a number.")
if answer != int(entryWidget.get().strip()):
tkMessageBox.showinfo("Answer", "INCORRECT!")
else:
tkMessageBox.showinfo("Answer", "CORRECT!")
# create a Tkinter window
root = Tk()
root.title("Math Quiz")
root["padx"] = 40
root["pady"] = 20
# Create a text frame to hold the text Label and the Entry widget
textFrame = Frame(root)
#Create a Label in textFrame
entryLabel = Label(textFrame)
entryLabel["text"] = "Answer:"
entryLabel.pack(side=LEFT)
# Create an Entry Widget in textFrame
entryWidget = Entry(textFrame)
entryWidget["width"] = 50
entryWidget.pack(side=LEFT)
textFrame.pack()
#directions
directions = ('Click start to begin. You will be asked a series of questions.')
instructions = Label(root, text=directions, width=len(directions), bg='orange')
instructions.pack()
# this will be a global flag
count_flag = True
answer = Questions()
Sub = lambda: Submit(answer, entryWidget)
#stopwatch = lambda: start(answer)
# create needed widgets
label = Label(root, text='0.0')
btn_submit = Button(root, text="Submit", command = Sub)
btn_start = Button(root, text="Start", command = start)
btn_submit.pack()
btn_start.pack()
label.pack()
# start the event loop
root.mainloop()
Your problem is with how you're calling the Questions() method. You only ask for the answer once with
answer = Questions()
and you do this before you press start (which is why it shows up before you hit start)
To fix it you could use code like this:
from Tkinter import*
import time
import tkMessageBox
import random
def Questions():
number1 = random.randrange(1,25)
number2 = random.randrange(1,50)
answer = number1 + number2
prompt = ("Add " + str(number1) + " and " + str(number2))
label1 = Label(root, text=prompt, width=len(prompt), bg='yellow')
label1.pack()
return answer
def start():
global count_flag
global answer
answer = Questions()
count_flag = True
count = 0.0
while True:
if count_flag == False:
break
# put the count value into the label
label['text'] = str(count)
# wait for 0.1 seconds
time.sleep(0.1)
# needed with time.sleep()
root.update()
# increase count
count += 0.1
def Submit(answer, entryWidget):
""" Display the Entry text value. """
global count_flag
count_flag = False
print answer
if entryWidget.get().strip() == "":
tkMessageBox.showerror("Tkinter Entry Widget", "Please enter a number.")
if answer != int(entryWidget.get().strip()):
tkMessageBox.showinfo("Answer", "INCORRECT!")
else:
tkMessageBox.showinfo("Answer", "CORRECT!")
# create a Tkinter window
root = Tk()
root.title("Math Quiz")
root["padx"] = 40
root["pady"] = 20
# Create a text frame to hold the text Label and the Entry widget
textFrame = Frame(root)
#Create a Label in textFrame
entryLabel = Label(textFrame)
entryLabel["text"] = "Answer:"
entryLabel.pack(side=LEFT)
# Create an Entry Widget in textFrame
entryWidget = Entry(textFrame)
entryWidget["width"] = 50
entryWidget.pack(side=LEFT)
textFrame.pack()
#directions
directions = ('Click start to begin. You will be asked a series of questions.')
instructions = Label(root, text=directions, width=len(directions), bg='orange')
instructions.pack()
# this will be a global flag
count_flag = True
Sub = lambda: Submit(answer, entryWidget)
#stopwatch = lambda: start(answer)
# create needed widgets
label = Label(root, text='0.0')
btn_submit = Button(root, text="Submit", command = Sub)
btn_start = Button(root, text="Start", command = start)
btn_submit.pack()
btn_start.pack()
label.pack()
# start the event loop
root.mainloop()
In this code the answer is updated every time you hit start and only updates when you hit start.