在Tkinter的 Toplevel类中更新标签文本
I am writing a Python app using tkinter for revising topics. -> 我正在用tkinter编写一个用于复习主题的Python应用。
It has a master (parent) window listing several topics as radio buttons, and a second (child) window which opens when the user selects the topic to be tested on from the list. -> 它有一个主窗口(父窗口),用单选按钮列出若干主题;还有一个第二个窗口(子窗口),在用户从列表中选择要测试的主题时打开。
Each topic has a separate Python script (which are imported to this script). In each imported script, there is a question bank. A randomly chosen question is returned by 'randomQn()' function in each script. -> 每个主题都有一个独立的Python脚本(会被导入到这个脚本中)。在每个导入的脚本里,存在一个题库。每个脚本中的randomQn() 函数会返回一个随机选中的题目。
The Second window displays the question. It is defined as a 'toplevel' Class. -> 第二个窗口显示题目。它被定义为一个 'toplevel' 类。
I have defined a tkinter label called 'Qn' which displays the random question, and a button called 'Next Question'. Upon pressing this button, I want to update the label's text (i.e., "Qn"'s text) each time. -> 我定义了一个名为 'Qn' 的tkinter标签来显示随机题目,还有一个名为 'Next Question' 的按钮。每次按下这个按钮时,我都想更新这个标签的文本(也就是Qn的文本)。
My problem is, I am unable to update the self.Qn label's text using self.Qn.update(text=.....) method inside the button's defintion. How can I update the Label's text when the 'Next question' button is pressed? -> 我的问题是,在按钮的定义中,无法使用self.Qn.update(text=.....) 方法来更新self.Qn标签的文本。如何在按下 'Next question' 按钮时更新标签的文本?
I get the following error - -> 我得到以下错误 -
> Button(self, text="Next Question",command=lambda:self.Qn.config(self.getQuestion())).pack(padx=10, pady=20, fill="y")
^^^^^^^^^^^^^^
>
> AttributeError: 'NoneType' object has no attribute 'config'
My code is below - -> 我的代码如下 -
import tkinter
from tkinter import *
from tkinter.ttk import *
import topic1
import topic2
import topic3
master = Tk()
master.title("Exam Revision")
master.minsize(150, 450)
Label(master, text="Select the topic to test, or select 'Random topic'").pack(padx=5, pady=15, fill="x")
test_topics = ["topic1", "topic2", "topic3"]
variable = StringVar(master, f"{test_topics[0]}")
for topic in test_topics:
Radiobutton(
master,
text=topic,
variable=variable,
value=topic,
).pack(anchor="w", padx=10, pady=2)
class NewWindow(Toplevel):
def __init__(self, master=None):
super().__init__(master)
self.title(f"{variable.get()}")
self.geometry("550x150")
self.question_to_ask = self.getQuestion()
self.Qn = tkinter.Label(self, text=self.question_to_ask).pack(padx=10, pady=10, fill="x")
Button(self, text="Next Question", command=self.Qn.config(self.getQuestion())).pack(padx=10, pady=20, fill="y")
def getQuestion(self):
if variable.get() == 'topic1':
return topic1.randomQn()
elif variable.get() == 'topic2':
return topic2.randomQn()
elif variable.get() == 'topic3':
return topic3.randomQn()
else:
return "No question found"
begin_button = Button(master, text="Test")
begin_button.bind("<Button>", lambda e: NewWindow(master)) # Bind the event
begin_button.pack(pady=20, fill="y")
master.mainloop()
解决方案
The problem is not what you think. In this code, you are assuming that Tk's function calls can be chained: -> 问题并不像你想的那么简单。在这段代码中,你以为Tk的函数调用可以链式调用:
self.Qn = tkinter.Label(self, text=self.question_to_ask).pack(padx=10, pady=10, fill="x")
Button(self, text="Next Question", command=self.Qn.config(self.getQuestion())).pack(padx=10, pady=20, fill="y")
Tk is an antique, created before before chaining was thought of. The Label.pack method returns None, and that's what gets stored in self.Qn. -> Tk是个古董,早在连锁调用被提出之前就已经存在。Label.pack 方法返回 None,这就是被存储在 self.Qn 中的东西。
Do -> 请执行
self.Qn = tkinter.Label(self, text=self.question_to_ask)
self.Qn.pack(padx=10, pady=10, fill="x")
Button(self, text="Next Question", command=self.Qn.config(self.getQuestion())).pack(padx=10, pady=20, fill="y")
and you should be happier. -> 这样你就会更顺手。