0

私は長い実行中のバックグラウンド(デーモン)プロセスとwxベースのUIを持つアプリを持っています。バックグラウンドプロセスは、実行中にデーモンプロセスのステータス更新を取得するために、UIが読み取るべきマルチプロセッシング.JoinableQueue()にメッセージを置きます。私が抱えている問題は、AwaitStatusReportThreadClassインスタンスがUIにメッセージを渡している間にUIが応答を停止することです。下のコードを実行し、ウィンドウのサイズを変更しようとすると、アプリケーションは応答していないと表示します。私はPython27 32ビットを使用して、Windows 7上でこれを実行しているwx Phoenix UIを更新するために、スレッドが結合可能なキューメッセージに応答するようにするにはどうすればよいですか?

、wxPythonのの4.0.0a3(フェニックス)

私のアプリは、様々なPythonのファイルで構成されているが、私は以下のコードでエラーを再現することができました。それはかなり簡単です。私はAwaitStatusReportThreadClassというクラスを作成して、hereのpub/subメソッドを使ってUIを更新しました。このクラスの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)

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() 
       wx.CallAfter(self.postMessage, msg) 

      except: 
       pub.sendMessage("Failed")   

    def postMessage(self, msg): 
     pub.sendMessage("UI", msg=msg) 
関連する問題