Tkinter Math Quiz - python

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.

Related

tkinter freezes due to after() method

The problem is the .after() method inside the 'get_content' function. The delay freezes the whole program. I tried solving it with threading but I can't figure it out. I tried a lot of variations. I will just post the code with the last one! Any suggestions? (The code still needs some fixes here and there but the freezing issue is really annoying and I want to get rid of this first)
import random
import tkinter as tk
from sentences import sentences
import threading
from PIL import ImageTk, Image
root = tk.Tk()
root.title("Speed typing test")
root.geometry('700x700')
# Dynamic labels
entry_text = tk.StringVar()
seconds = tk.IntVar()
# Stopwatch
def seconds_counter(*args):
if not entry_text.get():
seconds.set(0)
else:
counter = 0
while counter < 100:
counter += 1
root.update()
root.after(1000)
seconds.set(counter)
global total_time
total_time = counter
if entry_text.get() == sentence:
final = (len(entry.get()) / 5) / (0.1 * total_time)
final_lbl = tk.Label(root, text=f"WPM: {final}")
final_lbl.pack()
entry.delete(0, tk.END)
seconds.set(0)
word_list = sentence.split(' ')
total_words = len(word_list)
total_words_lbl = tk.Label(root, text=f'Total words: {total_words}')
total_words_lbl.pack()
counter = 0
break
x = threading.Thread(target=seconds_counter)
x.start()
sentence = random.choice(sentences)
sentence = sentence.strip('.')
# Create widgets
logo = ImageTk.PhotoImage(Image.open('images/logo.png'))
logo_lbl = tk.Label(image=logo)
sentence_lbl = tk.Label(root, text=sentence)
entry = tk.Entry(root, width=500, textvariable=entry_text)
seconds_lbl = tk.Label(root, textvariable=seconds)
# Place widgets
logo_lbl.pack()
sentence_lbl.pack()
entry.pack()
seconds_lbl.pack()
entry_text.trace('w', seconds_counter)
def stop():
root.destroy()
# command=quit freezes for some reason
btn_quit = tk.Button(root, text='Quit', command=stop)
btn_quit.pack()
root.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:

How to get data from a command run in a button

I fixed the previous problem I had with the function, but now I'm not sure how to get the changed variables from the function to change the label.
from tkinter import *
import tkinter.messagebox
import random
def testTrue(firstNo,secondNo):
if firstNo + secondNo == int(entry1.get()):
firstNo = random.randint(1,15)
secondNo = random.randint(1,15)
problem = ("What is",firstNo,"+",secondNo)
tkinter.messagebox.showinfo("Answer", "Correct")
elif firstNo + secondNo != entry1.get():
tkinter.messagebox.showinfo("Answer", "Wrong, try again!")
main = Tk()
entryType = IntVar()
firstNo = random.randint(1,15)
secondNo = random.randint(1,15)
problem = ("What is",firstNo,"+",secondNo)
label1 = Label(main,text=problem).grid(row=0, sticky=E)
entry1 = Entry(main,textvariable=entryType)
entry1.grid(row=0,column=1)
submitButton = Button(main,text="Submit",command=lambda: testTrue(firstNo,secondNo)).grid(columnspan=2,row=2)
main.mainloop()

Python: Tkinter stopping due to while loop

I am trying to run a while loop inside my program, but when the while loop is in place, the code stops, and the tkinter window does not open. How do I solve this? It should be so that the code writes out two random numbers, and then when the correct answer is input, it should re-loop.
from tkinter import *
import random
root = Tk()
#Frames
topFrame = Frame(root) # I want an invisible container in root
topFrame.pack()
bottomFrame = Frame(root) # I want an invisible container in root
bottomFrame.pack(side=BOTTOM)
#End Of Frames
#Addition Question Maker
AnswerBox = Entry(topFrame)
AnswerBox.grid(row=0,column=4)
EqualsSign = Label(topFrame, text="=").grid(row=0,column=3)
AdditionSign = Label(topFrame, text="+").grid(row=0,column=1)
NewQuestion = True
while NewQuestion == True:
AdditionQuestionLeftSide = random.randint(0, 10)
AdditionQuestionRightSide = random.randint(0, 10)
global Total
Total = AdditionQuestionLeftSide + AdditionQuestionRightSide
AdditionQuestionRightSide = Label(topFrame, text= AdditionQuestionRightSide).grid(row=0,column=0)
AdditionQuestionLeftSide= Label(topFrame, text= AdditionQuestionLeftSide).grid(row=0,column=2)
answer = None
def OutputAnswerText(event):
global answer
answer = AnswerBox.get()
if Total == int(answer):
Correct = Label(topFrame, text="Correct").grid(row=2,column=3)
NewQuestion = True
else:
Correct = Label(topFrame, text="Wrong").grid(row=2,column=3)
AnswerBox.bind('<Return>', OutputAnswerText)
root.mainloop()
Instead of making a while loop, I suggest making NewQuestion a function. The function gets called initially, then if the answer is correct the function gets called again. Here is my code for the function, along with an automatic entry delete option to remove the need to backspace your answer after inputting a correct answer.
from tkinter import *
import random
root = Tk()
#Frames
topFrame = Frame(root) # I want an invisible container in root
topFrame.pack()
bottomFrame = Frame(root) # I want an invisible container in root
bottomFrame.pack(side=BOTTOM)
#End Of Frames
#Addition Question Maker
AnswerBox = Entry(topFrame)
AnswerBox.grid(row=0,column=4)
EqualsSign = Label(topFrame, text="=").grid(row=0,column=3)
AdditionSign = Label(topFrame, text="+").grid(row=0,column=1)
def NewQuestion():
AdditionQuestionLeftSide = random.randint(0, 10)
AdditionQuestionRightSide = random.randint(0, 10)
global Total
Total = AdditionQuestionLeftSide + AdditionQuestionRightSide
AdditionQuestionRightSide = Label(topFrame, text= AdditionQuestionRightSide).grid(row=0,column=0)
AdditionQuestionLeftSide= Label(topFrame, text= AdditionQuestionLeftSide).grid(row=0,column=2)
answer = None
return
NewQuestion()
def OutputAnswerText(event):
global answer
global AnswerBox
answer = AnswerBox.get()
if Total == int(answer):
Correct = Label(topFrame, text="Correct").grid(row=2,column=3)
AnswerBox.delete(0, END)
NewQuestion()
else:
Correct = Label(topFrame, text="Wrong").grid(row=2,column=3)
AnswerBox.bind('<Return>', OutputAnswerText)
root.mainloop()
You have an infinite loop:
while NewQuestion == True:
There is no place where NewQuestion can become false (and no break in the loop). So the loop is infinite.
Also:
EqualsSign = Label(topFrame, text="=").grid(row=0,column=3)
doesn't work because grid returns None. If you want to keep a reference to the widget, you have to use the two-lines version like in:
AnswerBox = Entry(topFrame)
AnswerBox.grid(row=0,column=4)

Python timer in math game Tkinter

I'm looking to add a timer for my simple math game. So far everything works just fine, the user gets questions when pressing the button and is given feedback on the answer. I want to add a timer for the user to see how much time it takes to answer the multiplication. This is the final part of my prototype to this mathgame. I want the timer to start when the user clicks "nytt tal" which means new number in swedish, and to stopp when the user clicks "svar" which means answer in swedish. Here is my code.
from Tkinter import *
import tkMessageBox
import random
import time
import sys
# Definition for the question asked to user
def fraga1():
global num3
num3 = random.randint(1, 10)
global num4
num4 = random.randint(1, 10)
global svar1
svar1 = num3 * num4
label1.config(text='Vad blir ' + str(num3) + '*' + str(num4) + '?')
entry1.focus_set()
#The answer giving feedback based on answer
def svar1():
mainAnswer = entry1.get()
if len(mainAnswer) == 0:
tkMessageBox.showwarning(message='Skriv in några nummer!')
return
if int(mainAnswer) != svar1:
tkMessageBox.showwarning(message='Tyvärr det rätta svaret: ' + str(svar1))
else:
tkMessageBox.showinfo(message='RÄTT!! :)')
#The quit button definition
def quit():
global root
root.destroy()
#Definition for the timer this part doesnt work
def start():
global count_flag
fraga1()
count_flag = True
count = 0.0
while True:
if count_flag == False:
break
label['text'] = str(count)
time.sleep(0.1)
root.update()
count += 0.1
#Window code
root = Tk()
root.title("multiplikations tidtagning")
root.geometry('800x500')
count_flag = True
# Welcome message in labels
label2 = Label(root, text="Hej!\n Nu ska vi lösa lite matteproblem!")
label2.config(font=('times', 18, 'bold'), fg='black', bg='white')
label2.grid(row=0, column=0)
#Instructions how to play in labels
label3 = Label(root, text="Instruktioner!\n För att starta ett spel tryck på nyttspel")
label3.config(font=('times', 12, 'bold'), fg='black', bg='white')
label3.grid(row=2, column=2)
#other label
label1 = Label(root)
label1.grid(row=2, column=0)
# entry widget for the start button
entry1 = Entry(root)
entry1.grid(row=3, column=0)
# restart gives a new question
entry1.bind('', func=lambda e:checkAnswer())
#Buttons
fragaBtn = Button(root, text='Nytt tal', command=fraga1)
fragaBtn.grid(row=4, column=0)
svarButton = Button(root, text='Svar', command=svar1)
svarButton.grid(row=4, column=1)
quit_bttn = Button(root, text = "Avsluta", command=quit)
quit_bttn.grid(row=5, column=0)
root.mainloop()
I think what you need is this .
from Tkinter import *
import time
class StopWatch(Frame):
""" Implements a stop watch frame widget. """
def __init__(self, parent=None, **kw):
Frame.__init__(self, parent, kw)
self._start = 0.0
self._elapsedtime = 0.0
self._running = 0
self.timestr = StringVar()
self.makeWidgets()
def makeWidgets(self):
""" Make the time label. """
l = Label(self, textvariable=self.timestr)
self._setTime(self._elapsedtime)
l.pack(fill=X, expand=NO, pady=2, padx=2)
def _update(self):
""" Update the label with elapsed time. """
self._elapsedtime = time.time() - self._start
self._setTime(self._elapsedtime)
self._timer = self.after(50, self._update)
def _setTime(self, elap):
""" Set the time string to Minutes:Seconds:Hundreths """
minutes = int(elap/60)
seconds = int(elap - minutes*60.0)
hseconds = int((elap - minutes*60.0 - seconds)*100)
self.timestr.set('%02d:%02d:%02d' % (minutes, seconds, hseconds))
def Start(self):
""" Start the stopwatch, ignore if running. """
if not self._running:
self._start = time.time() - self._elapsedtime
self._update()
self._running = 1
def Stop(self):
""" Stop the stopwatch, ignore if stopped. """
if self._running:
self.after_cancel(self._timer)
self._elapsedtime = time.time() - self._start
self._setTime(self._elapsedtime)
self._running = 0
def Reset(self):
""" Reset the stopwatch. """
self._start = time.time()
self._elapsedtime = 0.0
self._setTime(self._elapsedtime)
def main():
root = Tk()
sw = StopWatch(root)
sw.pack(side=TOP)
Button(root, text='Start', command=sw.Start).pack(side=LEFT)
Button(root, text='Stop', command=sw.Stop).pack(side=LEFT)
Button(root, text='Reset', command=sw.Reset).pack(side=LEFT)
Button(root, text='Quit', command=root.quit).pack(side=LEFT)
root.mainloop()
if __name__ == '__main__':
main()
P.S: Fit this in your code I just implemented the basic timer in tkinter.
well if you're using a tkinter you're use the function
object.after(100, defineFunction)
the first parent is the milisecond
this'll apply to python3.x but 2.7 i cant be sure since i dont pratice that format
Use a global variable storing current time when person presses start. Then when the user presses svar in your function svar, just fetch current time, substract them from one another and you get time taken, then reset the global var to 0 also and voila, you have the time taken
I can suggest additional solution with threading.
I hold a small timer in one of my projects and it run as a different thread and gets updated each second:
import threading
import tkinter as tk
import time
root = tk.Tk()
timer = tk.Text(root, width=5, height=1)
timer.insert(tk.INSERT, "00:00")
timer.pack()
def show_time():
start = time.time()
seconds = 0
while True:
if time.time() - start > 1:
seconds += int(time.time() - start)
start = time.time()
cur_index = timer.index(tk.INSERT)
cur_index = str(int(cur_index[0]) - 1) + cur_index[1:]
timer.delete(cur_index, tk.INSERT)
timer.insert(tk.INSERT, str(int(seconds / 60)) + ":" + str(seconds % 60))
root.update()
thread = threading.Thread(target=show_time)
thread.start()
I think you can use "after".
You create a widget...
time = 60 #60 seconds for example
widget = Tkinter.Label().pack()
def count():
global time
if time > 0:
time -= 1
widget.config(text="Time left: " + str(time))
widget.after(1000, count)
I use python 3x
Sorry

Categories

Resources