Bond 007
Bond 007

Reputation: 220

Return to loop after tkinter button function

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

Answers (2)

Bond 007
Bond 007

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

Paul M.
Paul M.

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

Related Questions