0

장기 실행 백그라운드 (데몬) 프로세스와 wx 기반 UI가있는 앱이 있습니다. 백그라운드 프로세스는 실행중인 데몬 프로세스에서 상태 업데이트를 얻기 위해 UI가 읽어야하는 다중 처리 .JoinableQueue()에 메시지를 넣습니다. 내가 겪고있는 문제는 AwaitStatusReportThreadClass 인스턴스가 UI에 메시지를 전달하는 동안 UI가 응답하지 않게됩니다. 아래 코드를 실행 한 다음 창 크기를 조정하려고하면 앱이 응답하지 않는 것으로 표시됩니다. 스레드가 결합 가능 대기열 메시지에 응답하여 wx Phoenix UI를 업데이트하도록하려면 어떻게합니까?

나는 Python27 32 비트, 내 애플 다양한 파이썬 파일로 구성되어

wxPython에의 4.0.0a3 (피닉스)를 사용하여 Windows 7이 실행 해요,하지만 난 아래의 코드 오류를 재현 할 수 있었다. 꽤 간단합니다. here을 설명하는 pub/sub 메서드를 사용하여 UI를 업데이트하기 위해 AwaitStatusReportThreadClass라는 클래스를 만들었습니다. 이 클래스의 init 메소드에는 상태 메시지를 확인하는 무한 루프가 있습니다. 하나가 발견되면 StatusBar 메시지를 업데이트합니다.

import multiprocessing 
import threading 
import wx 
import sys 
from wx.lib.pubsub import pub 


class AwaitStatusReportThreadClass(threading.Thread): 
    """This class should pass messages to the UI class""" 
    def __init__(self, messageQueue): 
     """Init worker Thread Class""" 
     self.messageQueue = messageQueue 

     threading.Thread.__init__(self) 
     self.start() 

    def run(self): 
     """This code executes when the thread is run""" 

     KeepRunningStatusThread = True 
     while KeepRunningStatusThread: 
      sys.stdout.flush() 

      try: 
       msg = self.messageQueue.get() 
       self.messageQueue.task_done() 
      except: 
       pass 

      if msg == "Shutdown": 
       # Kill this thread 
       KeepRunningStatusThread = False 

      else: 
       pub.sendMessage("UI", msg=msg) 


class UI2(wx.Frame): 
    """This class is the UI""" 
    def __init__(self, taskQueue, messageQueue, stopQueue, parent=None): 

     self.taskQueue = taskQueue 
     self.messageQueue = messageQueue 
     self.stopQueue = stopQueue 

     wx.Frame.__init__(self, parent, title="TestApp") 

     #Main panel 
     sizerMain = wx.BoxSizer(wx.VERTICAL) 

     # Add the status bar 
     panelStatusBar = wx.Panel(self) 
     sizerStatusBar = wx.BoxSizer(wx.HORIZONTAL) 
     panelStatusBar.SetSizer(sizerStatusBar) 

     self.StatusBar_Main = wx.StatusBar(panelStatusBar, wx.NewId()) 
     sizerStatusBar.Add(self.StatusBar_Main, 1, wx.EXPAND | wx.LEFT | wx.RIGHT, 2) 

     #Add the status bar sizer to the main sizer 
     sizerMain.Add(panelStatusBar, 0, wx.EXPAND) 

     #Add the progress bar 
     panelProgressBar = wx.Panel(self) 
     sizerProgressBar = wx.BoxSizer(wx.HORIZONTAL) 
     panelProgressBar.SetSizer(sizerProgressBar) 
     self.Gauge_ProgressBar = wx.Gauge(panelProgressBar, wx.NewId()) 
     sizerProgressBar.Add(self.Gauge_ProgressBar, 1, wx.EXPAND) 
     sizerMain.Add(panelProgressBar,0,wx.EXPAND) 

     #Layout the frame 
     self.SetSizer(sizerMain) 
     self.SetAutoLayout(1) 
     sizerMain.Fit(self) 
     self.Layout() 
     self.Show(show=True) 

     #Subscribe to messages from the messageQueue 
     pub.subscribe(self.HandleStatusUpdate, "UI") 
     AwaitStatusReportThreadClass(self.messageQueue) 

    def HandleStatusUpdate(self, msg): 
     """ 
     This def updates the UI from a pubsub subscription 

     """ 
     StatusBar = self.StatusBar_Main 
     StatusBar.PushStatusText(msg) 


if __name__ == "__main__": 

    #Make multiprocessing work when app is frozen 
    multiprocessing.freeze_support() 

    taskQueue = multiprocessing.JoinableQueue() #Specifies tasks to be completed by the GenInst process 
    messageQueue = multiprocessing.JoinableQueue() #Holds status messages/progress messages to update the message zone and progress bar in the UI 
    stopQueue = multiprocessing.JoinableQueue() #Allows cancel operation button to function 

    messageQueue.put("Please wait while the GenInst background process starts...") 

    #Start the UI 
    app = wx.App(False) 
    frame = UI2(taskQueue=taskQueue, messageQueue=messageQueue, stopQueue=stopQueue) 
    app.MainLoop() 

어떤 조언이 필요합니까?

답변

0

글쎄, 그 해결책은 쉬웠다. 나는 그것이 미래에 누구에게 도움이 될지를 대비하여 여기에 남겨 둘 것입니다.

메시지를 게시하는 데 wx.CallAfter를 사용하도록 AwaitStatusReportThreadClass를 다시 구성해야했습니다. 클래스에 postMessage 함수를 추가하고이를 사용하여 호출했습니다. wx.CallAfter(self.postMessage, msg)