破坏 tkinter 主循环(使用 canvas 和按钮),奇怪的行为
Destroying tkinter mainloop (with canvas and buttons), strange behaviour
我有 root=Tk.Tk()
,其中包含标签 (Tk.Label)、输入表单 (Tk.Entry)、按钮 (Tk.Button) 和嵌入式 matplotlib FigureCanvasTkAgg
.这是一个简单的脚本,它绘制了用户指定的系数 (a, b, c) 的二次函数。但是我对破坏主循环有一些问题和误解。
我预料到,主 window 的简单关闭(通过单击右上角的 "x")也应该导致退出 mainloop。如果我要注释与嵌入 canvas 相关的所有代码,我的脚本就是这种情况。但是对于嵌入式 FigureCanvasTkAgg
,它不会发生(因此需要再次中断 运行 脚本的内核)。正如在其他 questions 中讨论的那样,有两种退出主循环的方法:root.quit()
和 root.destroy()
。所以我也尝试使用这些方法退出主循环:
def close_all():
root.quit()
root.destroy()
按新按钮:
button_quit=Tk.Button(root, text="Quit", command=close_all)
button_quit.grid(row=5, column=1)
通过覆盖 "x" 按钮:
root.protocol('WM_DELETE_WINDOW', close_all)
我的问题:
这两种方法都奏效了。但是为什么如果我只使用 root.destroy()
,root.mainloop()
仍然会执行?为什么 mainloop 在关闭 window 后没有被销毁?为什么这个问题会导致FigureCanvasTkAgg
?
嵌入matplotlib图是通过以下方式完成的(如果有助于解释):
fig, ax = plt.subplots()
canvas = FigureCanvasTkAgg(fig, master=root)
plot_widget = canvas.get_tk_widget()
#(plotting with plt.plot(..))
canvas.show()
plot_widget.grid(row=6, column = 0, columnspan=3)
close_all()
函数在这个意义上起作用,从主循环执行退出,脚本执行停止。但是仍然有一些奇怪的行为。有var_a = Tk.StringVar()
这样的变量,用于以某种方式从输入字段接收数据:
L_a = Tk.Label(master=root, width=10, height=2, bd =2, text="a")
E_a = Tk.Entry(master=root, width=10, bd =2, textvariable=var_a)
和
def get_value():
if not check_if_float(var_a.get()) or not check_if_float(var_b.get()) or not check_if_float(var_c.get()):
showerror(title = "Error", message = "Invalid entry. Enter integer or decimal numbers, please")
return None
a=float(var_a.get())
b=float(var_b.get())
c=float(var_c.get())
所以问题和奇怪的行为是,在执行代码一次后,关闭 main window(通过单击右上角的 "x",或单击 "Quit" 按钮), 在接下来的执行代码中收到空var_a, var_b, var_c。如果内核中断,并且代码再次运行,它会正常工作(运行 在 jupyter notebook 中)。我不知道为什么会这样。
这是因为您没有为变量提供主变量,因此它们默认为创建的第一个 Tk() 实例,即使它已被销毁。修复只是提供正确的根:
var_a = Tk.StringVar(root)
这通常不是问题,因为在极少数情况下您会想要多次调用 Tk()。
我有 root=Tk.Tk()
,其中包含标签 (Tk.Label)、输入表单 (Tk.Entry)、按钮 (Tk.Button) 和嵌入式 matplotlib FigureCanvasTkAgg
.这是一个简单的脚本,它绘制了用户指定的系数 (a, b, c) 的二次函数。但是我对破坏主循环有一些问题和误解。
我预料到,主 window 的简单关闭(通过单击右上角的 "x")也应该导致退出 mainloop。如果我要注释与嵌入 canvas 相关的所有代码,我的脚本就是这种情况。但是对于嵌入式 FigureCanvasTkAgg
,它不会发生(因此需要再次中断 运行 脚本的内核)。正如在其他 questions 中讨论的那样,有两种退出主循环的方法:root.quit()
和 root.destroy()
。所以我也尝试使用这些方法退出主循环:
def close_all():
root.quit()
root.destroy()
按新按钮:
button_quit=Tk.Button(root, text="Quit", command=close_all)
button_quit.grid(row=5, column=1)
通过覆盖 "x" 按钮:
root.protocol('WM_DELETE_WINDOW', close_all)
我的问题:
这两种方法都奏效了。但是为什么如果我只使用
root.destroy()
,root.mainloop()
仍然会执行?为什么 mainloop 在关闭 window 后没有被销毁?为什么这个问题会导致FigureCanvasTkAgg
? 嵌入matplotlib图是通过以下方式完成的(如果有助于解释):fig, ax = plt.subplots() canvas = FigureCanvasTkAgg(fig, master=root) plot_widget = canvas.get_tk_widget() #(plotting with plt.plot(..)) canvas.show() plot_widget.grid(row=6, column = 0, columnspan=3)
close_all()
函数在这个意义上起作用,从主循环执行退出,脚本执行停止。但是仍然有一些奇怪的行为。有var_a = Tk.StringVar()
这样的变量,用于以某种方式从输入字段接收数据:L_a = Tk.Label(master=root, width=10, height=2, bd =2, text="a") E_a = Tk.Entry(master=root, width=10, bd =2, textvariable=var_a)
和
def get_value(): if not check_if_float(var_a.get()) or not check_if_float(var_b.get()) or not check_if_float(var_c.get()): showerror(title = "Error", message = "Invalid entry. Enter integer or decimal numbers, please") return None a=float(var_a.get()) b=float(var_b.get()) c=float(var_c.get())
所以问题和奇怪的行为是,在执行代码一次后,关闭 main window(通过单击右上角的 "x",或单击 "Quit" 按钮), 在接下来的执行代码中收到空var_a, var_b, var_c。如果内核中断,并且代码再次运行,它会正常工作(运行 在 jupyter notebook 中)。我不知道为什么会这样。
这是因为您没有为变量提供主变量,因此它们默认为创建的第一个 Tk() 实例,即使它已被销毁。修复只是提供正确的根:
var_a = Tk.StringVar(root)
这通常不是问题,因为在极少数情况下您会想要多次调用 Tk()。