Python Forum
GUI calculation mistake
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
GUI calculation mistake
#1
Hi all,

Can anyone tell me why my calculation (total_hscore (at the end of the code) is coming to zero please?
Thanks,

def openHistory():
    global total_hscore
  
    newWindow=Toplevel(mgui)
    newWindow.title("History")
    newWindow.configure(bg="dark red")
    newWindow.geometry("800x800")
    Label1=Label(newWindow,text="HISTORY",bg="dark red",fg="white").place(x=360,y=1)
    Label(newWindow,text="In which year did World War II end?",bg="dark red",fg="white").place(x=275,y=25)
    Label(newWindow,text="A. 1945",bg="dark red",fg="white").place(x=215,y=60)
    Label(newWindow,text="B. 1942",bg="dark red",fg="white").place(x=315,y=60)
    Label(newWindow,text="C. 1980",bg="dark red",fg="white").place(x=415,y=60)
    Label(newWindow,text="D. 2021",bg="dark red",fg="white").place(x=515,y=60)

    options = StringVar(newWindow)
    ho1=OptionMenu(newWindow,options, "A","B","C","D")
    ho1.config(bg="dark red",fg="white",width=10,height=1)
    ho1.place(x=305,y=100)

    if options=="A":
        hscore1=1
       
    else:
        hscore1=0
    
    Label(newWindow,text="In which year did World War II start?",bg="dark red",fg="white").place(x=275,y=135)
    Label(newWindow,text="A. 2016",bg="dark red",fg="white").place(x=215,y=175)
    Label(newWindow,text="B. 1914",bg="dark red",fg="white").place(x=315,y=175)
    Label(newWindow,text="C. 1939",bg="dark red",fg="white").place(x=415,y=175)
    Label(newWindow,text="D. 1936",bg="dark red",fg="white").place(x=515,y=175)

    options = StringVar(newWindow)
    ho2=OptionMenu(newWindow,options, "A","B","C","D")
    ho2.config(bg="dark red",fg="white",width=10,height=1)
    ho2.place(x=305,y=205)

    if options=="C":
        hscore2=1
    else:
        hscore2=0
    
    Label(newWindow,text="What was the name of the machine used to create German and Japanese codes?",bg="dark red",fg="white").place(x=110,y=240)
    Label(newWindow,text="A. Axis",bg="dark red",fg="white").place(x=215,y=275)
    Label(newWindow,text="B. Enola",bg="dark red",fg="white").place(x=315,y=275)
    Label(newWindow,text="C. Blitz",bg="dark red",fg="white").place(x=415,y=275)
    Label(newWindow,text="D. Enigma",bg="dark red",fg="white").place(x=515,y=275)
    
    options = StringVar(newWindow)
    ho3=OptionMenu(newWindow,options, "A","B","C","D")
    ho3.config(bg="dark red",fg="white",width=10,height=1)
    ho3.place(x=305,y=310)
    

    if options =="D":
        hscore3=1
    else:
        hscore3=0
    
    Label(newWindow,text="Which countries fought on the Eastern Front of World War II? ",bg="dark red",fg="white").place(x=200,y=350)
    Label(newWindow,text="A. Germany/Soviet Union",bg="dark red",fg="white").place(x=105,y=400)
    Label(newWindow,text="B. Britain/Germany",bg="dark red",fg="white").place(x=300,y=400)
    Label(newWindow,text="C. Switzerland/Italy",bg="dark red",fg="white").place(x=450,y=400)
    Label(newWindow,text="D. United States/Japan",bg="dark red",fg="white").place(x=600,y=400)

    options = StringVar(newWindow)
    ho4=OptionMenu(newWindow,options, "A","B","C","D")
    ho4.config(bg="dark red",fg="white",width=10,height=1)
    ho4.place(x=305,y=440)
    
    if options=="A":
        hscore4=1
    else:
        hscore4=0
    
    Label(newWindow,text="What was the code name for the allied invasion of Normandy?",bg="dark red",fg="white").place(x=200,y=480)
    Label(newWindow,text="A. VJ Day",bg="dark red",fg="white").place(x=180,y=520)
    Label(newWindow,text="B. VE Day",bg="dark red",fg="white").place(x=280,y=520)
    Label(newWindow,text="C. D-Day",bg="dark red",fg="white").place(x=380,y=520)
    Label(newWindow,text="D. French Resistance",bg="dark red",fg="white").place(x=480,y=520)

    options = StringVar(newWindow)
    ho5=OptionMenu(newWindow,options, "A","B","C","D")
    ho5.config(bg="dark red",fg="white",width=10,height=1)
    ho5.place(x=305,y=560)

    
    if options =="C":
        hscore5=1
    else:
        hscore5=0
   
    Label(newWindow,text="In 1945 which two Japanese cities were nuclear bombs detonated?",bg="dark red",fg="white").place(x=160,y=600)
    Label(newWindow,text="A. Hiroshima/Nagasaki",bg="dark red",fg="white").place(x=170,y=640)
    Label(newWindow,text="B. Tokyo/Hiroshima",bg="dark red",fg="white").place(x=340,y=640)
    Label(newWindow,text="C. Tokyo/Nagasaki",bg="dark red",fg="white").place(x=490,y=640)

    options = StringVar(newWindow)
    ho6=OptionMenu(newWindow,options, "A","B","C","D")
    ho6.config(bg="dark red",fg="white",width=10,height=1)
    ho6.place(x=305,y=668)

    if options=="A":
        hscore6=1
    else:
        hscore6=0

    hbt20=Button(newWindow,text="Continue",bg="dark red",fg="white",width=14,height=1,command=openSport).place(x=305,y=703)

    
    total_hscore=hscore1+hscore2+hscore3+hscore4+hscore5+hscore6
    print(total_hscore)
Reply
#2
Because you got all the answers wrong. Actually you got all the answers wrong twice.

From your code:
    options = StringVar(newWindow)
    ho2=OptionMenu(newWindow,options, "A","B","C","D")
    ho2.config(bg="dark red",fg="white",width=10,height=1)
    ho2.place(x=305,y=205)
 
    if options=="C":
        hscore2=1
    else:
        hscore2=0
This creates an OptionMenu and binds it to a StringVar(). So far, so good. But then it tries to test the value of the StringVar() and that is where you are twice wrong. First off, to get the value selected by the OptionMenu you use options.get(). options is a StringVar and it is never going to match "C". options.get() may match "C", but not until you fix your other problem.

Your second problem is you don't wait for the questions to be answered. Your program tests the answer as soon as the widgets are made. None of the OptionMenus are set at this time, so options.get() returns 0.

You need to wait until all the questions are answered before you can calculate the score. This means you'll need a different "options" StringVar() for each question, and you only "get()" the answers from those options when you press the button to continue.
Reply
#3
You should not hardcode questions into a test program. The program should be set up to ask any question, and the questions for a particular test should be data, probably read in from a file or retrieved from a database. This is poor example of what I am talking about.
from tkinter import *

answers = []

HISTORY = [
    {   'Q': "In which year did World War II end?",
        'choices': ("A. 1945", "B. 1942", "C. 1980", "D. 2021"),
        'A': "A"},
    {   'Q': "What was the name of the machine used to create German and Japanese codes?",
        'choices': ("A. Axis", "B. Enola", "C. Blitz", "D. Enigma"),
        'A': "D"},
    {   'Q': "Which countries fought on the Eastern Front of World War II?",
        'choices': ("A. Germany/Soviet Union", "B. Britain/Germany", "C. Switzerland/Italy", "D. United States/Japan"),
        'A':"A"},
    {   'Q': "What was the code name for the allied invasion of Normandy?",
        'choices': ("A. VJ Day", "B. VE Day", "C. D-Day",  "D. French Resistance"),
        'A': "C"},
    {   'Q': "In 1945 which two Japanese cities were nuclear bombs detonated?",
        'choices': ("A. Hiroshima/Nagasaki", "B. Tokyo/Hiroshima", "C. Tokyo/Nagasaki"),
        'A': "A"
    }]
 
def quiz(window, title, questions, bg='white', fg='black'):
    window.title(title)
    window.configure(bg=bg)
    Label(window, text=title, bg=bg, fg=fg).pack()

    for question in questions:
        Label(window, text='', bg=bg, fg=fg).pack()
        Label(window, text=question['Q'], bg=bg, fg=fg).pack()

        choices = []
        for choice in question['choices']:
            Label(window, text=choice, bg=bg, fg=fg).pack()
            choices.append(choice[0])
    
        answer = StringVar()
        option = OptionMenu(window, answer, *choices)
        option.configure(fg=fg, bg=bg)
        option.pack()

        answers.append((answer, question))
    
def score_quiz(questions):
    score = 0
    for answer, question in questions:
        if answer.get() == question['A']:
            score += 1
        else:
            choice = ord(question['A']) - ord('A')
            print(f'{question["choices"][choice]} is the answer to {question["Q"]}')
    print('Score =', score)

root = Tk()
quiz(root, 'History', HISTORY, 'red', 'white')
Button(root, text='Check Answers', command=lambda: score_quiz(answers)).pack(pady=10)

root.mainloop()
In this example HISTORY is a list of questions. Each question has a question ('Q'), answer ('A'), and a list of choices ('choices'). The quiz function draws a window to display all the questions and collect the answers. The score_quiz() function checks the answers against the questions and tabulates a score.
Reply
#4
here's my attempt at a quiz generator quiz generator.
I use a separate text(.txt) file formatted- question-> answers -> solution.
the tkinter script reads the lines of the file and generates the quiz using labels,
and buttons for answers. I use stringVars to keep track of scoring. One suggestion use a combobox instead of creating a menu.
Reply
#5
Thank you. They are really helpful points.
Reply
#6
My head was stuck in the world of paper tests. The code is shorter, and the test better if you combine the choices with the answer. This code puts all the choices in the option menu.
import random
import tkinter as tk
 
answers = []
 
HISTORY = [
    {   'Q': "In which year did World War II end?",
        'A': ("1945", "1942", "1980", "2021")},
    {   'Q': "What was used to encript German and Japanese messages?",
        'A': ("Enigma", "Axis", "Enola", "Blitz", )},
    {   'Q': "Which countries fought on the Eastern Front of World War II?",
        'A': ("Germany/Soviet Union", "Britain/Germany", "Switzerland/Italy", "United States/Japan")},
    {   'Q': "What was the code name for the allied invasion of Normandy?",
        'A': ("D-Day",  "VJ Day", "VE Day", "French Resistance")},
    {   'Q': "In 1945 which two Japanese cities were nuclear bombs detonated?",
        'A': ("Hiroshima/Nagasaki", "Tokyo/Hiroshima", "Tokyo/Nagasaki"),
    }]
  
def quiz(window, title, questions, bg='white', fg='black'):
    window.title(title)
    window.configure(bg=bg)
    tk.Label(window, text=title, bg=bg, fg=fg).pack()
 
    for question in questions:
        tk.Label(window, text='', bg=bg, fg=fg).pack()
        tk.Label(window, text=question['Q'], bg=bg, fg=fg).pack()
 
        answer = tk.StringVar()
        choices = random.sample(question['A'], len(question['A']))
        option = tk.OptionMenu(window, answer, *choices)
        option.configure(fg=fg, bg=bg)
        option.pack()
 
        answers.append((answer, question))
     
def score_quiz(questions):
    score = 0
    for answer, question in questions:
        if answer.get() == question['A'][0]:
            score += 1
        else:
            print(f'{question["A"][0]} is the answer to {question["Q"]}')
    print('Score =', score)
 
root = tk.Tk()
quiz(root, 'History', HISTORY)
tk.Button(root, text='Check Answers', command=lambda: score_quiz(answers)).pack(pady=10)
 
root.mainloop()
My thinking about how to store the test questions was also stuck in the past. Instead of having a separate field for the answer, why not order the questions such that the first answer is always the correct answer. It makes it easier to write the questions. Of course we don't want a multiple choice test to use "A" as the correct answer for every question, so the choices get shuffled each time the test is taken.
Reply


Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020