wxPython - изменение текста строки состояния из дочернего процесса - PullRequest
2 голосов
/ 13 мая 2019

Мой код (Ubuntu 18.04, Python 2.7, wxPython 4) создает пользовательский интерфейс со строкой состояния, а затем запускает дочерний процесс.Новый процесс пытается обновить текст строки состояния, но изменение не отображается в строке состояния.

В примере кода показано, что я пытаюсь выполнить:

    import wx, multiprocessing

    class MyFrame(wx.Frame):
        def __init__(self, parent, title):
            wx.Frame.__init__(self, parent, title=title, size=(300,200))
            self.sb = self.CreateStatusBar()
            self.sb.SetStatusText('Original text')
            self.Show(True)

    def doWork():
        print 'In doWork'
        print frame.sb.GetStatusText()
        frame.sb.SetStatusText('New stuff')
        print frame.sb.GetStatusText()

    p = multiprocessing.Process(target=doWork, args=())
    app = wx.App(False)
    frame = MyFrame(None, 'Status Text')
    p.start()
    app.MainLoop()

Процесс doWork может получить доступ к исходному тексту строки состояния и распечатать его, и, по-видимому, ему удалось установить текст состояния (на основе результата второй печати).Но текст, отображаемый в строке состояния, не меняется.Есть ли способ обновить текст строки состояния из отдельного процесса?

1 Ответ

1 голос
/ 14 мая 2019

Программы Gui запускаются в основном цикле, и я считаю, что обновления должны происходить в основном цикле. (Кто-то может уточнить здесь или действительно, скажите мне, что я не прав).

Обычно способ достижения этого - генерировать событие из wx.lib.newevent или использовать что-то вроде pubsub. Однако они обычно генерируются с помощью Thread, а не Process, опять же, кто-то может поправить меня (я такой же нечеткий, как и следующий человек по этому вопросу).

См. Здесь: Многопроцессорная обработка Python, PyAudio и wxPython
и здесь: wxpython 3.0 и многопроцессорность - обновление графического интерфейса пользователя из фонового процесса
для справочной информации

и здесь для подробного разрешения: https://wiki.wxpython.org/MultiProcessing

Ответ, по-видимому, заключается в использовании Queue из multiprocessing и использовании wx.Timer для периодической проверки этой очереди на наличие обновлений.

Я разработал быстрый скрипт для иллюстрации решения с помощью вашего кода. По крайней мере, это должна быть разумная отправная точка, с которой вы можете прогрессировать.
Помимо первоначального изменения текста статуса, он также обновляется каждые 5 секунд, просто чтобы доказать свою правоту.

import multiprocessing
import wx

class MyFrame(wx.Frame):
    def __init__(self, parent, title):
        wx.Frame.__init__(self, parent, title=title, size=(300,200))
        self.sb = self.CreateStatusBar()
        self.sb.SetStatusText('Original text')
        self.Show(True)
        self.timer = wx.Timer(self)
        self.process_timer = wx.Timer(self)
        self.Bind(wx.EVT_TIMER, self.poll, self.timer)
        self.Bind(wx.EVT_TIMER, self.process, self.process_timer)
        self.timer.Start(1000)
        self.process_timer.Start(5000)
        self.cnt = 0

    # Poll for a queue entry with which to update the statusbar
    def poll(self, event):
        print("Polling")
        if q.empty():
            return
        q_mess = q.get()
        self.sb.SetStatusText(q_mess)

    #Fire off a new process every 5 seconds to demonstrate the update
    def process(self, event):
        self.cnt += 1
        p = multiprocessing.Process(target=doWork, args=(q,self.cnt))
        p.start()

def doWork(q,cnt=0):
    print ('In doWork')
    q.put("New status "+str(cnt))

q = multiprocessing.Queue()
p = multiprocessing.Process(target=doWork, args=(q,0))
app = wx.App(False)
frame = MyFrame(None, 'Status Text')
p.start()
app.MainLoop()

enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...