如何从生成的进程 (multiprocessing.Process) 更新 Tkinter 标签?
How can I update Tkinter label from a spawned process (multiprocessing.Process)?
总结:在 Python 中,当我从派生进程更新 Tkinter 标签文本时,GUI 上的标签没有更新,尽管派生进程已执行。我怎样才能让它从生成的进程更新?
我正在 Lubuntu 20.04
中使用 Python 2.7.2
编辑:我也试过 Python 3.8,不得不安装 python3-tk extra,稍微改变一下语法(打印命令后的括号并用 tkinter 替换 Tkinter),但问题仍然存在。
结束编辑
这是我的示例代码,可以独立运行以供试用:
from Tkinter import *
from multiprocessing import Process
# simple Label change invoked from "simple" button
def bnAction_sync():
print "bnAction_sync"
changeLabel()
print "bnAction_sync done"
# asynchronous label change invoked from Async button
def bnAction_async():
print "bnAction_async"
p = Process(target=changeLabel)
p.start()
print "bnAction_Async done"
def changeLabel():
print "change label"
lbl['text'] = "Text changed"
### Apr 19 2021:
### uncommenting the following line really updates label but makes program crash ###
# root.update_idletasks
print "change label done"
root = Tk()
btnSync = Button(root, text="simple", command=bnAction_sync)
btnSync.pack()
btnAsync = Button(root, text="async", command=bnAction_async)
btnAsync.pack()
lbl = Label(root, text="Initial text")
lbl.pack()
root.mainloop()
如果我按下“简单”按钮,标签中的文本会更新。一切顺利。
但是:
如果我按下“异步”按钮,
- 正如您可以通过我提供的打印件验证的那样,异步过程开始了,
- 标签文本更新行被执行。
- 但是:这是我的问题: GUI 上的标签没有显示更新的文本。
我想这样做的原因:
因为我开始了一个漫长的 运行ning 生成过程,之后 我想更新标签。然而,所有其他进程应该 运行 并行。所以我创建了一个函数f,依次包含long 运行ning函数和标签更新函数。我想异步调用 f 。
所以原则上:
def longprocess():
code...
def updatelabel_after_longprocess():
code...
def f():
longprocess()
updatelabel_after_longprocess()
p = Process(target=f)
p.start()
do other things immediately
我在某处读到,刷新已暂停,而脚本仍在 运行ning。
我尝试了一些 p.join 插入,但没有成功。
请帮忙,谢谢!
您不太可能能够通过其他流程更新您的标签。这可能是可能的,但它会非常复杂。相反,我建议您创建一个线程,在另一个进程中启动昂贵的代码,然后等待更新 GUI,直到该进程完成:
from multiprocessing import Process
from threading import Thread
def longprocess():
# do whatever you need here, it can take a long time
def updatelabel_after_longprocess():
# do whatever GUI stuff you need here, this will be run in the main process
def thread_helper():
process = Process(target=longprocess)
process.start()
process.join() # this waits for the process to end
updatelabel_after_longprocess()
if __name__ == "__main__":
t = Thread(target=thread_helper)
t.start()
# do whatever else you have to do in parallel here
t.join()
总结:在 Python 中,当我从派生进程更新 Tkinter 标签文本时,GUI 上的标签没有更新,尽管派生进程已执行。我怎样才能让它从生成的进程更新?
我正在 Lubuntu 20.04
中使用 Python 2.7.2编辑:我也试过 Python 3.8,不得不安装 python3-tk extra,稍微改变一下语法(打印命令后的括号并用 tkinter 替换 Tkinter),但问题仍然存在。 结束编辑
这是我的示例代码,可以独立运行以供试用:
from Tkinter import *
from multiprocessing import Process
# simple Label change invoked from "simple" button
def bnAction_sync():
print "bnAction_sync"
changeLabel()
print "bnAction_sync done"
# asynchronous label change invoked from Async button
def bnAction_async():
print "bnAction_async"
p = Process(target=changeLabel)
p.start()
print "bnAction_Async done"
def changeLabel():
print "change label"
lbl['text'] = "Text changed"
### Apr 19 2021:
### uncommenting the following line really updates label but makes program crash ###
# root.update_idletasks
print "change label done"
root = Tk()
btnSync = Button(root, text="simple", command=bnAction_sync)
btnSync.pack()
btnAsync = Button(root, text="async", command=bnAction_async)
btnAsync.pack()
lbl = Label(root, text="Initial text")
lbl.pack()
root.mainloop()
如果我按下“简单”按钮,标签中的文本会更新。一切顺利。
但是: 如果我按下“异步”按钮,
- 正如您可以通过我提供的打印件验证的那样,异步过程开始了,
- 标签文本更新行被执行。
- 但是:这是我的问题: GUI 上的标签没有显示更新的文本。
我想这样做的原因: 因为我开始了一个漫长的 运行ning 生成过程,之后 我想更新标签。然而,所有其他进程应该 运行 并行。所以我创建了一个函数f,依次包含long 运行ning函数和标签更新函数。我想异步调用 f 。 所以原则上:
def longprocess():
code...
def updatelabel_after_longprocess():
code...
def f():
longprocess()
updatelabel_after_longprocess()
p = Process(target=f)
p.start()
do other things immediately
我在某处读到,刷新已暂停,而脚本仍在 运行ning。 我尝试了一些 p.join 插入,但没有成功。
请帮忙,谢谢!
您不太可能能够通过其他流程更新您的标签。这可能是可能的,但它会非常复杂。相反,我建议您创建一个线程,在另一个进程中启动昂贵的代码,然后等待更新 GUI,直到该进程完成:
from multiprocessing import Process
from threading import Thread
def longprocess():
# do whatever you need here, it can take a long time
def updatelabel_after_longprocess():
# do whatever GUI stuff you need here, this will be run in the main process
def thread_helper():
process = Process(target=longprocess)
process.start()
process.join() # this waits for the process to end
updatelabel_after_longprocess()
if __name__ == "__main__":
t = Thread(target=thread_helper)
t.start()
# do whatever else you have to do in parallel here
t.join()