【问题标题】:python running task in the background while allowing tkinter to be activepython在后台运行任务,同时允许tkinter处于活动状态
【发布时间】:2014-08-22 05:37:18
【问题描述】:

当我的程序执行时,python GUI 冻结。这是我的主要代码。我可以在做线程方面得到一些帮助吗?所以执行发生在后台,如果我想结束执行,我仍然可以使用 GUI 中的“x”按钮吗?目前我只是要求用户关闭 cmd 以结束程序。

if __name__ == "__main__":

    root = Tk() 
    root.title('Log')
    root.geometry("400x220") 
    font1=('times', 15)
    font2=('times', 10)
    #Label inside root 
    Label(root, relief=GROOVE, font=font2, text="level").pack() 
    variable = StringVar(root)
    variable.set("INFO") # default value

    w = OptionMenu(root, variable, "CRITICAL", "DEBUG")
    w.pack()
    Button(root, font=font1, background= "yellow", text='START',command=main).pack()
    Label(root, text="To end just close the CMD window").pack()

    root.mainloop()

【问题讨论】:

  • 在线程中到底应该做什么?您打算更新 GUI 吗?请注意,Tkinter 不是线程安全的。
  • main 函数在哪里?有问题的代码在哪里?也许你可以用tk.After() 做到这一点?

标签: python tkinter python-multithreading


【解决方案1】:

更新:原来 Button 回调是自动运行的 launch 因为函数对象没有被设置为回调,被调用的函数本身是。修复方法是替换回调lambda: spawnthread(fcn),以便将函数对象设置为回调。答案已更新以反映这一点。很抱歉错过了。


当您尝试运行其他功能时,GUI 主循环将冻结,并且无法自行重新启动(因为它已冻结。)

假设您要与 GUI 主循环一起运行的命令是 myfunction

进口:

import time
import threading
import Queue

你需要设置一个ThreadedClient类:

class ThreadedClient(threading.Thread):
    def __init__(self, queue, fcn):
        threading.Thread.__init__(self)
        self.queue = queue
        self.fcn = fcn
    def run(self)
        time.sleep(1)
        self.queue.put(self.fcn())

def spawnthread(fcn):
    thread = ThreadedClient(queue, fcn)
    thread.start()
    periodiccall(thread)

def periodiccall(thread):
    if(thread.is_alive()):
        root.After(100, lambda: periodiccall(thread))

然后您希望调用该函数的小部件改为调用spawnthread 函数:

queue = Queue.Queue()

Button(root, text='START',command=lambda: spawnthread(myfunction)).pack() #<---- HERE

注意我正在从我拥有的多线程 tkinter GUI 中调整它;我的所有框架都包含在类中,所以这可能有一些错误,因为我不得不对其进行一些调整。

【讨论】:

  • 我不断收到错误第 26 行,在 spawnthr ead 周期性调用(线程)文件 X,第 30 行,在周期性调用之后(100,lambda:periodiccall(thread)) NameError:全局名称“之后”是未定义
  • 啊。尝试使用 root.after(...) 代替。
  • @user2980048 甚至是 root.After(...)。好久没用过tkinter了,不知道哪个最好。
  • 感谢使用 root.After(..) 后现在可以正常工作。但是,为什么我的 main() 函数在我没有点击开始按钮的情况下执行?
  • 之前没有点击开始按钮就运行了吗?
猜你喜欢
  • 2015-05-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-18
  • 1970-01-01
  • 2015-04-01
  • 2021-09-08
相关资源
最近更新 更多