Tkinter问题与多个回调函数和after()的使用有关



我正在编写一段很长的代码,我想在多个窗口中多次输入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或其他事件。

相关内容

最新更新