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()
Другие вопросы по тегам