我正在编写一段很长的代码,我想在多个窗口中多次输入GUI。
代码太长了,如果我把它放在这里就没有多大意义了,但这是我的代码布局:
callback1():
do something
tkinter stuff, using callback1()
...
lots of other code (none to do with tkinter)
...
callback2():
do something else
tkinter stuff using callback2()
some more code (none to do with tkinter)
mainloop()
很抱歉结构模糊,但这或多或少是我代码的布局。然而,问题是,mainloop()似乎永远无法到达,而我在回调之间的其他代码依赖于GUI的输入,因此它崩溃了。
我试过:
callback1():
do something
after(500, callback1)
tkinter stuff, using callback1()
...
lots of other code (none to do with tkinter)
...
callback2():
do something else
after(500, callback1)
tkinter stuff using callback2()
some more code (none to do with tkinter)
after(0, callback1)
after(0, callback2)
mainloop()
但是运气不好。有人能帮我正确使用after(或任何其他函数)吗?这样我就可以显示GUI了?
像tkinter这样的GUI框架是事件驱动的。它们在启动mainloop()
时开始运行。在此之前的一切基本上都是设置和内务管理。
在主循环开始后,它们运行的代码中只有部分是回调,这些回调已附加到按钮等接口元素或after
计时器上。
这些回调必须相对较短,并且不应花费很长时间。GUI工具箱调用您提供的函数来处理主循环中的事件。因此,当您的回调正在运行时,没有进一步的事件被处理,GUI实际上被冻结了。如果这只需要一点时间(比如50毫秒),没有人会注意到。但是,如果您想运行一个需要几秒钟才能完成的计算,那么在不冻结GUI的情况下,您无法在回调中执行此操作。
您可以考虑在第二个线程中执行长时间运行的作业。但在CPython中,由于技术原因,一次只能有一个线程执行Python字节码。然而(尤其是在Python3中)线程被迫定期放弃CPU,因此这可能是一个可行的解决方案。
另一种解决方案是使用multiprocessing
将长时间运行的作业分发给一个单独的进程。在这种情况下,您必须通过例如Queue
来设置进程之间的通信。
您不能这样组织代码。大概,你有类似的东西:
import tkinter as tk
mainwindow = tk.Tk()
mainwindow.geometry("300x200")
mainwindow.title("MyWindow")
label = tk.Label(mainwindow, text="Enter stuff, then click the button.")
label.pack()
var = tk.StringVar()
entry = tk.Entry(mainwindow, textvariable=var)
entry.pack()
#callback1():
def onclick():
#do something with var.get() ?
pass
button = tk.Button(mainwindow, text="click me", command=onclick)
button.pack()
#lots of other code (none to do with tkinter):
print("The value I need is: {}".format(var.get()))
mainwindow.mainloop()
该程序的输出为:
我需要的值是:
您需要将代码放入回调函数或回调函数调用的另一个函数中:
def my_func():
print("The value I need: {}".format(var.get()))
def onclick():
#do something with var.get()
my_func()
button = tk.Button(mainwindow, text="click me", command=onclick)
现在,输出类似于:
我需要的值是:10
tkinter
是一个GUI框架,它对窗口中发生的事件做出响应。响应事件的方法是将代码封装在回调函数中,并将该函数传递给tkinter,然后tkinter将在适当的时间调用该函数。您不能在tkinter程序的中间编写任意代码。
after()
方法似乎不合适,因为它本质上说:
在主循环开始后,执行此函数。
您可以将执行延迟多少秒,但这并不意味着用户届时已经输入了所需的数据。您想要做的是在用户输入数据后执行代码,通常您通过响应按钮单击来执行代码,其中按钮显示Submit
或其他事件。