【问题标题】:How can I make this code for a multiple choice quiz work in Tkinter?如何使此代码在 Tkinter 中用于多项选择测验?
【发布时间】:2021-01-12 17:39:32
【问题描述】:

我打算在标签中显示文本,然后在底部有 4 个按钮供用户选择

问题存储在一个非常原始的记事本文件中,我用冒号分隔每一行以分隔主题、问题、正确答案,最后是 3 个错误答案

英语:什么是专有名词?:一个人或一个地方:一个对象:一个描述词:一个做事词

数学:什么是 4 x 9:36:37:28:29

以下是 Python 代码 我需要打印变量 question[1] 这是问题 然后我需要有 4 个按钮显示以下变量,问题 [2]、问题 [3]、问题 [4]、问题 [5]

我不知道如何“tkintify”这个,所以任何帮助将不胜感激。我的特别困难是将变量转换为“tkinter 变量”,尤其是在创建“文本”参数为变量的按钮时

提前致谢

Python 代码:

f1 = f.readlines()
f.close()

#Asks the user to pick a subject, in the project this
#will use your subject variable from where the user has
#chosen a subject by clicking a button
Subject = input("Pick a subject")

# Creates a blank list
questions = []

# Splits the list up by colon so we can find the subject, question,
# and correct answers. Subject = question[0], question = question[1],
# correct answer = question[2], incorrect answers = question[3] to question[5]
for question in f1:
    sQuestion = question.split(":")
    questions.append(sQuestion)

# Goes through the list of questions and only prints the correct subject
for question in questions:
    if question[0] == Subject:
        answer = input(question[1]+": "+question[2]+", "+question[3]+", "+question[4]+", "+question[5]+"?")
        # Checks to see if the user guess is correct
        if answer==question[2]:
            print("Correct")
        else:
            print("Incorrect")

【问题讨论】:

  • 恐怕你需要一个关于 tkinter 的教程。也许这个可以服务:realpython.com/python-gui-tkinter
  • 仅供参考,堆栈溢出是针对更具体的问题。是的,您确实提供了代码,但是解释如何“tkerize”这意味着几乎用您的代码编写整个程序,就像仅仅在加载数据的函数或方法中一样。

标签: python tkinter


【解决方案1】:

您的问题非常非常广泛,并不适合 Stackoverflow。不过,我将尝试为您提供一些一般性指导,因为我了解尝试学习 GUI 编程有多么困难。

概述

基于事件的编程与过程代码非常不同。您需要初始化 UI,然后设置函数来响应事件,而不是编写自上而下的代码。然后可以使用这些函数来更改显示。

我见过的一位最有才华的程序员给了我一个建议,即你应该始终从考虑你的数据结构开始。如果你已经很好地设计了你的数据,那么实现几乎是不言而喻的。如果你有糟糕的数据结构(例如:只是一堆随机变量),它会让程序非常难以编写和理解。

使用对象提问

那么,让我们从查看您的问题开始。它们是必须解析的一行文本。如果所有问题都是可以按主题存储在字典中的对象,那么编写 GUI 会更容易。

不必花哨,如果我们可以假设您的所有数据都已正确格式化,则定义可能看起来像这样:

class Question():
    def __init__(self, question_string):
        subject, question,answer1,answer2,answer3,answer4 = question_string.split(":")
        self.subject = subject
        self.question = question
        self.correct_answer = answer1
        self.answers = (answer1, answer2, answer3, answer4)

要创建一个问题,您可以从文件中传递一行。一旦你有了对象,就很容易得到主题、问题文本、正确答案和可能的答案。

>>> q = Question("English:What is a proper noun?:A person or a place:An object:A describing word:A doing word")
>>> print(q.question)
What is a proper noun?
>>> print(q.correct_answer)
A person or a place
>>> print(q.answers)
('A person or a place', 'An object', 'A describing word', 'A doing word')

这样,您可以遍历文件的行,为每一行创建一个对象。您可以将问题存储在列表或按主题组织的字典中。既然您说您希望用户选择一个主题,那么为每个主题创建一个带有键的字典是最有意义的。

可能看起来像这样:

questions = {"English": [], "Maths": []}
for row in f.readlines():
    question = Question(row)
    questions[question.subject].append(question)

创建图形用户界面

一般的想法是预先创建小部件,然后在选择问题时更新小部件。为此,我们将创建一个框架来容纳一个问题,并且在该框架中将有一个问题标签和四个单选按钮用于答案。单选按钮是正确的 UI 选择,因为它们代表了一个独特的选择。还会有一个标签显示答案是否正确。

首先,创建小部件以显示单个问题及其答案。

此代码假定您之前创建了一个名为 question_frameFrame。将小部件放在一个单独的框架中可以让您在将来更轻松地向您的 GUI 添加其他小部件。

单选按钮需要共享 tkinter 变量之一(StringVarIntVar 等)。这就是 tkinter 知道一次只能选择一个的方式,它提供了一种获取所选值的机制。我们将使用IntVar 并将其命名为answer_var

answer_var = tk.StringVar()
question_label = tk.Label(question_frame, width=80, anchor="w")
answer_radiobuttons = (
    tk.Radiobutton(question_frame, anchor="w", variable=answer_var, value=0),
    tk.Radiobutton(question_frame, anchor="w", variable=answer_var, value=1),
    tk.Radiobutton(question_frame, anchor="w", variable=answer_var, value=2),
    tk.Radiobutton(question_frame, anchor="w", variable=answer_var, value=3),
)

这会创建一个标签来显示“正确”或“不正确”

result_label = tk.Label(root)

最后,我们需要在框架中排列小部件

pack 在这里使用是因为它简单。如果您愿意,可以使用grid

question_label.pack(side="top", fill="x", anchor="w")
result_label.pack(side="bottom", fill="x")
for button in answer_radiobuttons:
    button.pack(side="top", fill="x", expand=True, anchor="w")

创建一个显示问题的函数

现在有了显示问题及其答案的小部件,并且现在我们有了一些问题对象,我们需要编写一个可以显示单个问题及其答案的函数。我们可以通过使用小部件的configure 方法来做到这一点,该方法允许在创建小部件后对其进行修改。

在以下示例中,答案是随机的,因此用户无法仅通过选择每个问题的第一个单选按钮来获得正确答案。此外,我们将使用一个全局变量来跟踪当前问题。

def show_question(question):
    global current_question
    current_question = question

    # configure the question label to display the question
    question_label.configure(text=question.question)

    # configure the radiobuttons to hold the answers
    answers = list(question.answers)
    random.shuffle(answers)
    for i in range(4):
        answer_radiobuttons[i].configure(text=answers[i])

    answer_var.set(-1)  # causes buttons to show as unselected

这样,您可以通过将任何问题传递给show_question 来显示任何问题。例如,您可以使用“下一步”按钮从问题列表中选择一个问题,然后将其显示在屏幕上。

创建一个函数来检查答案

现在我们有了一个保存问题的数据结构,以及一种显示问题的方法。现在我们需要一种方法来验证结果。 Radiobutton 小部件接受可用于此目的的 command 属性,或者您可以有一个“检查答案”按钮,或者您可以在用户尝试单击“下一个问题”按钮时调用该函数。无论如何,重点是创建一个进行检查的函数。如何触发取决于您。

我们知道单选按钮绑定到一个名为answer_var 的变量,并且该变量有一个返回值的get 方法。我们在列表中也有单选按钮,因此我们可以使用 cget 方法获取所选单选按钮的文本。这样,我们就可以将其与当前问题对象的正确答案进行比较。

看起来像这样:

def check_answer():
    choice = answer_var.get()
    answer = answer_radiobuttons[choice].cget("text")
    if answer == current_question.correct_answer:
        result_label.configure(text="Correct")
    else:
        result_label.configure(text="Incorrect")

作为如何使用它的示例,我们可以要求单选按钮在配置时调用此函数。我们可以通过添加command 属性来更改单选按钮的创建方式:

answer_radiobuttons = (
    tk.Radiobutton(main_frame, anchor="w", variable=answer_var, value=0, command=check_answer),
    tk.Radiobutton(main_frame, anchor="w", variable=answer_var, value=1, command=check_answer),
    tk.Radiobutton(main_frame, anchor="w", variable=answer_var, value=2, command=check_answer),
    tk.Radiobutton(main_frame, anchor="w", variable=answer_var, value=3, command=check_answer),
)

总结

我遗漏了很多细节,但那是因为没有一种最好的方法可以做到这一点,而且您的问题非常广泛。但是,一般模式适用于大多数 GUI 程序:

  • 初始化您的数据
  • 初始化显示
  • 通过对用户的操作做出反应来更新显示

【讨论】:

  • 谢谢,这真的很有帮助。我非常感谢您在此回复中投入的时间。这是给我正在辅导的学生的,在此之前我从未使用过 tkinter,这就是我挣扎的原因!我会告诉他你的答案,让他通读一遍。再次感谢您
  • 嗨 Bryan - 我们遇到了一点麻烦,我希望如果我在此处添加评论,它可能会到达您的身边 for 循环遍历文本文件并加载所有问题 - 它只是直接跳到最后一个问题 有没有办法让 check_answer 函数在单击单选按钮时加载下一个问题?使用 Tkinter 时我真的脱离了我的舒适区,这让这个问题更难消化!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-12-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-09
  • 1970-01-01
  • 2020-07-18
相关资源
最近更新 更多