Python 2.7.2: как обновить метку Tkinter из порожденного процесса (multiprocessing.Process)? (ред: также Python 3.8)
Описание: В Python, когда я обновляю текст метки Tkinter из порожденного процесса, метка в графическом интерфейсе не обновляется, хотя порожденный процесс выполняется. Как мне сделать так, чтобы он обновлялся из порожденного процесса?
Я работаю с Python 2.7.2 в Lubuntu 20.04
РЕДАКТИРОВАТЬ: Я также пробовал с 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"
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()
Если я нажму «простую» кнопку, текст в метке обновится. Все хорошо.
Но: если я нажму кнопку "асинхронно",
- как вы можете убедиться по предоставленным мною распечаткам, начинается асинхронный процесс,
- выполняется строка обновления текста метки.
- Но: Вот моя проблема: метка на графическом интерфейсе не отображает обновленный текст.
Причина, по которой я хочу сделать это таким образом: потому что я запускаю длительный порожденный процесс, после которого я хочу обновить метку. Однако все остальные процессы должны выполняться параллельно. Итак, я создал функцию f, последовательно содержащую долгосрочную функцию и функцию обновления метки. Я хочу вызвать 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
Где-то я читал, что обновление приостановлено, пока скрипт все еще работает. Я попробовал несколько вставок p.join, но безуспешно.
Пожалуйста, помогите, спасибо!
1 ответ
Маловероятно, что у вас получится сделать обновление ярлыка из другого процесса работоспособным. Возможно, это возможно, но это будет очень сложно. Вместо этого я предлагаю создать поток, который запускает дорогостоящий код в другом процессе, а затем ждет обновления графического интерфейса пользователя, пока процесс не будет завершен:
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()