简体   繁体   中英

How can I update Tkinter label from a spawned process (multiprocessing.Process)?

Summary: In Python when I update a Tkinter label text from a spawned process, the label on the GUI is not updated, although the spawned process is executed. How can I make it update from the spawned process?

Im am working with Python 2.7.2 in Lubuntu 20.04

EDIT : I also tried with Python 3.8, had to install python3-tk extra, change a little syntax (parentheses after print command and replacing Tkinter with tkinter), but problem still there looking identical. END EDIT

Here is my sample code working standalone to try out:

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()

If I press the "simple" button, text is updated in label. All good.

But: If I press "async" button,

  • as you can verify by the prints I have provided, the asynchronous process starts,
  • the label text updation line is executed.
  • But: Here is my problem: The label on the GUI is not displaying the updated text.

The reason I want to do it this way: Because I am starting a long running spawned process, after which I want to update the label. All other processes however should run in parallel. So I created a function f, containing the long running function and the label update function sequentially. I want to call f asynchronously. So in principle:

def longprocess():
   code...
def updatelabel_after_longprocess():
   code...
def f():
   longprocess()
   updatelabel_after_longprocess()

p = Process(target=f)
p.start()
do other things immediately

Somewhere I read, that refresh is suspended, while a script is still running. I tried some p.join inserts with no luck.

Please help, thanks!

It's unlikely that you'll be able to make updating your label from another process work. It might be possible, but it will be very complicated. What I'd suggest instead is that you make a thread that launches the expensive code in another process, and then waits to update the GUI until after the process is done:

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()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM