Reputation: 220
I want my quiz to wait for user interactions with the buttons of different values and then decide if the "text" inside the button matches the answer to the question, This system works but instead of waiting for the user to pick one option. It goes through all the questions outputting all the answers and questions, doesn't require interactions.
I tried to use partial
and lambda
to make it go to the function after the user pressed something and it works but it doesn't accept button presses and goes through every question. And threading basically does the same thing but stays at the first question and shows a million popups of every option without user interaction.
Is there an easier way of doing this and allow the function to see what button was pressed or am I doing it right?
listofdifnumbers
contains all the question numbers for difficulties so let's say the user picked 10 easy, 20 normal, and 30 hard questions then listofdifnumbers
will be [10,20,30]
.
questions
contains all the questions in the form of a nested dictionary, E.g. {1: {'Question': 'WWW stands for?', 'fakes': 'World Word Web', 'Answer': 'World Wide Web'}, 2: {'Question': 'Which of the following is a group of independent computers attached to one another through communication media', 'fakes': 'Internet', 'Answer': 'Network'}}
def wrongcheck(num):
global Questionnum, questionseasy1, questionsmedium1, questionshard1,answer,score
global choice, correctorwrong
global score1of1
if score1of1<=listofdifnumbers[0]:
if num == 1:
if showeasybutton1["text"]== questions[score1of1].get("Answer"):
picked = showeasybutton1["text"]
choice.append(picked)
correctorwrong.append("correct")
error.showerror("Correct",("%s is the correct answer \n Welldone \n Score +1"%(picked)),icon="info")
score+=1
else:
picked = showeasybutton1["text"]
choice.append(picked)
correctorwrong.append("Wrong")
error.showerror("Wrong",("%s was the correct answer,\n You chose %s"%(questions[score1of1].get("Answer"),picked)),icon="info")
elif num == 2:
if showeasybutton2["text"]== questions[score1of1].get("Answer"):
picked = showeasybutton2["text"]
choice.append(picked)
correctorwrong.append("correct")
error.showerror("Correct",("%s is the correct answer \n Welldone \n Score +1"%(picked)),icon="info")
score+=1
else:
picked = showeasybutton2["text"]
choice.append(picked)
correctorwrong.append("Wrong")
error.showerror("Wrong",("%s was the correct answer,\n You chose %s"%(questions[score1of1].get("Answer"),picked)),icon="info")
print(correctorwrong)
print(choice)
print(score1of1)
def quizinterfacestarter():
global timer
global login
global login, lookwhereat2,quizconfigurationframe, AllquizSTATSlabel
global Questionnum, questionseasy1, questionsmedium1, questionshard1, MaxMarkss, MaxMarks
global questions
print(questions)
print(len(questions))
screen_width = login.winfo_screenwidth()
screen_height = login.winfo_screenheight()
for widget in login.winfo_children():
widget.destroy()
height1 = int(screen_height)/4
height2 = int(screen_height)*3
tophalfframe= Frame(login,width=int(screen_width),height=height1,bg="light coral")
tophalfframe.grid(sticky="new")
goback= PhotoImage(file='icons/goback.png')
exitframebutton= Button(tophalfframe,image=goback,text="Return ",compound="left",bg='aquamarine',relief='flat', font="Ariel 25",command=subjectgoback)
exitframebutton.grid(column=1,sticky="nws")
movealonglabel = Label(text=" ",bg="light coral")
movealonglabel.grid(row=1,column=2,columnspan=2)
QuestionLabelAsker = Label(tophalfframe,text="Questions Loading ...",relief='raised', font="Ariel 20")
QuestionLabelAsker.grid(column=5,row=1,columnspan=7)
if timer == True:
initiatetimerstart = time.strftime("%H:%M:%S")
global fsos,showeasybutton1,showeasybutton2,answer
showeasybutton1=Button(login,text="Answer 1",font="Ariel 30")
showeasybutton1.grid(sticky="new")
showeasybutton2=Button(login,text="Answer 2",font="Ariel 30")
showeasybutton2.grid(sticky="new")
showmediumbutton=Button(login,text="Answer 3",font="Ariel 30")
showmediumbutton.grid(sticky="new")
showhardbutton=Button(login,text="Answer 4",font="Ariel 30")
showhardbutton.grid(sticky="new")
global choice, correctorwrong,score
choice = []
correctorwrong =[]
score=0
sonumisone=0
global score1of1
score1of1=0
##works up to here
while sonumisone != (sum(listofdifnumbers)+1):
sonumisone+=1
if sonumisone<=listofdifnumbers[0]:
score1of1+=1
QuestionLabelAsker["text"]=questions[score1of1].get("Question")
answers = [questions[score1of1].get("fakes"),questions[score1of1].get("Answer")]
fsos = r.choice(answers)
showeasybutton1["text"]= fsos
answers.remove(fsos)
showeasybutton2["text"]= answers[0]
showeasybutton2.config(command=lambda *args: wrongcheck(2))
showeasybutton1.config(command=lambda *args: wrongcheck(1))
showmediumbutton["state"]="disabled"
showhardbutton["state"]="disabled"
login.mainloop()
Upvotes: 0
Views: 374
Reputation: 220
Taking into account what you told me, I moved the whole question extractor to a new function and changed the while
statement to an if
statement and this does exactly what I wanted. Thanks to all those who answered.
def wrongcheck(num):
global Questionnum, questionseasy1, questionsmedium1, questionshard1,answer,score
global choice, correctorwrong
global score1of1
login.update()
if score1of1<=listofdifnumbers[0]:
if num == 1:
if showeasybutton1["text"]== questions[score1of1].get("Answer"):
picked = showeasybutton1["text"]
choice.append(picked)
correctorwrong.append("correct")
error.showerror("Correct",("%s is the correct answer \n Welldone \n Score +1"%(picked)),icon="info")
score+=1
else:
picked = showeasybutton1["text"]
choice.append(picked)
correctorwrong.append("Wrong")
error.showerror("Wrong",("%s was the correct answer,\n You chose %s"%(questions[score1of1].get("Answer"),picked)),icon="info")
elif num == 2:
if showeasybutton2["text"]== questions[score1of1].get("Answer"):
picked = showeasybutton2["text"]
choice.append(picked)
correctorwrong.append("correct")
error.showerror("Correct",("%s is the correct answer \n Welldone \n Score +1"%(picked)),icon="info")
score+=1
else:
picked = showeasybutton2["text"]
choice.append(picked)
correctorwrong.append("Wrong")
error.showerror("Wrong",("%s was the correct answer,\n You chose %s"%(questions[score1of1].get("Answer"),picked)),icon="info")
print(correctorwrong)
print(choice)
print(score1of1)
fixquizinterfaceproblem()
def fixquizinterfaceproblem():
global timer
global login, lookwhereat2,quizconfigurationframe, AllquizSTATSlabel
global Questionnum, questionseasy1, questionsmedium1, questionshard1, MaxMarkss, MaxMarks
global questions
global sonumisone,score1of1,score
if sonumisone != (sum(listofdifnumbers)+1):
sonumisone+=1
print(score1of1,sonumisone)
if sonumisone<=listofdifnumbers[0]:
score1of1+=1
login.update()
QuestionLabelAsker["text"]=questions[score1of1].get("Question")
answers = [questions[score1of1].get("fakes"),questions[score1of1].get("Answer")]
fsos = r.choice(answers)
showeasybutton1["text"]= fsos
answers.remove(fsos)
showeasybutton2["text"]= answers[0]
showeasybutton2.config(command=lambda *args: wrongcheck(2))
showeasybutton1.config(command=lambda *args: wrongcheck(1))
showmediumbutton["state"]="disabled"
showhardbutton["state"]="disabled"
else:
pass
login.mainloop()
def quizinterfacestarter():
global timer
global login
global login, lookwhereat2,quizconfigurationframe, AllquizSTATSlabel
global Questionnum, questionseasy1, questionsmedium1, questionshard1, MaxMarkss, MaxMarks
global questions
print(questions)
print(len(questions))
screen_width = login.winfo_screenwidth()
screen_height = login.winfo_screenheight()
for widget in login.winfo_children():
widget.destroy()
height1 = int(screen_height)/4
height2 = int(screen_height)*3
tophalfframe= Frame(login,width=int(screen_width),height=height1,bg="light coral")
tophalfframe.grid(sticky="new")
goback= PhotoImage(file='icons/goback.png')
exitframebutton= Button(tophalfframe,image=goback,text="Return ",compound="left",bg='aquamarine',relief='flat', font="Ariel 25",command=subjectgoback)
exitframebutton.grid(column=1,sticky="nws")
movealonglabel = Label(text=" ",bg="light coral")
movealonglabel.grid(row=1,column=2,columnspan=2)
global QuestionLabelAsker
QuestionLabelAsker = Label(tophalfframe,text="Questions Loading ...",relief='raised', font="Ariel 20")
QuestionLabelAsker.grid(column=5,row=1,columnspan=7)
if timer == True:
initiatetimerstart = time.strftime("%H:%M:%S")
global fsos,showeasybutton1,showeasybutton2,showmediumbutton, showhardbutton, answer
showeasybutton1=Button(login,text="Answer 1",font="Ariel 30")
showeasybutton1.grid(sticky="new")
showeasybutton2=Button(login,text="Answer 2",font="Ariel 30")
showeasybutton2.grid(sticky="new")
showmediumbutton=Button(login,text="Answer 3",font="Ariel 30")
showmediumbutton.grid(sticky="new")
showhardbutton=Button(login,text="Answer 4",font="Ariel 30")
showhardbutton.grid(sticky="new")
global choice, correctorwrong,score
choice = []
correctorwrong =[]
score=0
global sonumisone
sonumisone=0
global score1of1
score1of1=0
fixquizinterfaceproblem()
login.mainloop()
Upvotes: 0
Reputation: 10809
I know you may not be interested in starting over, but here is how I might implement such a program. Our main entry-point of the script is the main
function, which defines a list of "question objects" (really just dictionaries) which describe all questions and their associated answers. There are just two questions in total for this example, and each question has four possible answers. We instantiate an instance of our Application
class and run its .mainloop()
to start the event-loop. The application instance is initialized with our list of questions. It doesn't keep track of the question list directly, but rather, it creates an iterator of that list, such that we can iterate over the questions later using next
. The whole program works in an event-driven way - first, we create out widgets and set the layout. Then, we invoke goto_next_question
to grab the next question from our question iterator, and then we fill the text of the label and buttons. We also change all the buttons' callbacks, such that only one of them will lead us to the next question. When the user presses the button with the correct answer, we invoke goto_next_question
again, and keep going in this way until no questions remain:
import tkinter as tk
class Application(tk.Tk):
def __init__(self, questions, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.title("Questions")
self.geometry("256x128")
self.resizable(width=False, height=False)
self.grid_columnconfigure(0, weight=1)
self.grid_columnconfigure(1, weight=1)
self.grid_rowconfigure(0, weight=1)
self.grid_rowconfigure(1, weight=1)
self.grid_rowconfigure(2, weight=1)
self.questions = iter(questions)
self.question_label = tk.Label(self, text="hello world" * 3, borderwidth=2, relief="ridge")
self.question_label.grid(row=0, column=0, columnspan=2)
self.default_button_color = tk.Button().cget("bg")
self.buttons = []
for y in range(2):
for x in range(2):
button = tk.Button(self, text="123")
button.grid(row=y+1, column=x, sticky=tk.N + tk.S + tk.E + tk.W)
self.buttons.append(button)
self.goto_next_question()
def goto_next_question(self):
from random import shuffle
question = next(self.questions, None)
if question is None:
self.destroy()
return
shuffle(question["answers"])
self.question_label["text"] = question["text"]
for button, answer in zip(self.buttons, question["answers"]):
button["text"] = answer["text"]
button["bg"] = self.default_button_color
if answer["isCorrect"]:
button["command"] = self.goto_next_question
else:
button["command"] = lambda button=button: self.answered_wrong(button)
def answered_wrong(self, button):
from tkinter.messagebox import showerror
button["bg"] = "red"
showerror(message="Wrong!")
def main():
questions = [
{
"text": "What is the capitol of Switzerland?",
"answers": [
{
"text": "Bern",
"isCorrect": True
},
{
"text": "Zürich",
"isCorrect": False
},
{
"text": "Lucerne",
"isCorrect": False
},
{
"text": "Geneva",
"isCorrect": False
}
]
},
{
"text": "What is the height of Mount Everest?",
"answers": [
{
"text": "8,849m",
"isCorrect": True
},
{
"text": "7,994m",
"isCorrect": False
},
{
"text": "4,021m",
"isCorrect": False
},
{
"text": "10,119m",
"isCorrect": False
}
]
}
]
application = Application(questions)
application.mainloop()
return 0
if __name__ == "__main__":
import sys
sys.exit(main())
Upvotes: 2