2011-10-24 44 views
1

私はサブプロセスを使っていくつかのコマンドを起動するGUIアプリケーションを持っていますし、subprocess.Popen.stdoutから読み込んでwx.ProgressDialogを使ってこのコマンドの進行状況を示します。私はLinuxの下でアプリケーションを書いてきましたが、完璧にそこで動作しますが、私は今、Windowsの下でいくつかのテストを行っています、そして、進捗ダイアログを更新しようとすると、アプリケーションがハングアップするようです。エラーメッセージなど何もないので、何が起きているのか把握するのは難しいです。以下は、単純化されたコードです:wxPython +サブプロセス。 ProgressDialogはウィンドウの下では機能しません

サブプロセスは、メインスレッドでは、この方法により、別のスレッドで起動されます:

def onOk(self,event):   
    """ Starts processing """ 
    self.infotxt.Clear() 
    args = self.getArgs() 
    self.stringholder = args['outfile']     

    if (args):      
     cmd = self.buildCmd(args, True) 

     if (cmd): 
      # Make sure the output directory is writable. 
      if not self.isWritable(args['outfile']): 
       print "Cannot write to %s. Make sure you have write permission or select a different output directory." %os.path.dirname(args['outfile']) 
      else:     
       try: 
        self.thread = threading.Thread(target=self.runCmd,args=(cmd,)) 
        self.thread.setDaemon(True) 
        self.thread.start()      
       except Exception: 
        sys.stderr.write('Error starting thread') 

そしてここでは、RUNCMD方法です:

def runCmd(self, cmd): 
    """ Runs a command line provided as a list of arguments """ 
    temp = [] 
    aborted = False 
    dlg = None   
    for i in cmd: 
     temp.extend(i.split(' ')) 

    # Use wx.MutexGuiEnter()/MutexGuiLeave() for anything that accesses GUI from another thread      
    wx.MutexGuiEnter() 
    max = 100 
    stl = wx.PD_CAN_ABORT | wx.PD_APP_MODAL | wx.PD_ELAPSED_TIME | wx.PD_REMAINING_TIME 
    dlg = wx.ProgressDialog("Please wait", "Processing...", maximum = max, parent = self.frame, style=stl)        
    wx.MutexGuiLeave()    

    # This is for windows to not display the black command line window when executing the command 
    if os.name == 'nt': 
     si = subprocess.STARTUPINFO() 
     si.dwFlags |= subprocess.STARTF_USESHOWWINDOW 
     si.wShowWindow = subprocess.SW_HIDE 
    else: 
     si = None   

    try: 
     proc = subprocess.Popen(temp, shell=False, bufsize=1, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)    
    except Exception: 
     sys.stderr.write('Error executing a command. ')   

    # Progress dialog  
    count = 0 

    while True: 
     line=proc.stdout.readline() 
     count += 1   

     wx.MutexGuiEnter() 
     if dlg.Update(count) == (True, False): 
      print line.rstrip() 
      wx.MutexGuiLeave() 
      if not line: break 
     else: 
      print "Processing cancelled." 
      aborted = True 
      wx.MutexGuiLeave() 
      proc.kill() 
      break 

    wx.MutexGuiEnter() 
    dlg.Destroy() 
    wx.GetApp().GetTopWindow().Raise()   
    wx.MutexGuiLeave() 

    if aborted:    
     if os.path.exists(self.stringholder): 
      os.remove(self.stringholder) 

    dlg.Destroy() 
    proc.wait() 

ここでも、これはLinuxで正常に動作しますWindowsではフリーズします。もしdlg.Update()行を削除してもうまく動作します。サブプロセスの出力がメインウィンドウに表示され、ProgressDialogが表示されます。プログレスバーは動かないだけです。私は何が欠けていますか?

+0

私たちのコンピュータで実際に試すことができる非常に小さな実行可能なアプリケーションに問題を絞り込むことができれば素晴らしいと思います。 – Fenikso

+0

解決策が見つからない場合は後でやろうとしますが、テストするには単純なCアプリが必要になるかもしれません。私がサブプロセスで実行しているコマンドはバッファリングを避けるように変更されているので、proc.stdout.readline()は出力が生成されるとすぐに出力を取得します。それ以外の場合は、パイプへの書き込み時にフル・バッファリングを使用するC stdout実装のため、コマンドが終了するまで出力を使用できません。これはLinux上で 'unbuffer'を使って解決することができますが、WindowsではCコードをいくつか修正する必要があります。 wx.CallAfterを使用して問題を解決できない場合は、後で返信します。 – jaho

答えて

0

wx.MutexGuiEnterwx.MutexGuiLeaveを使用しないでください。 wx.CallAfterを使用して別のスレッドからGUIを更新することができます。 wxアプリケーションでこれらのミューテックスを使用する人は誰も見たことがありません。チュートリアルやスレッドの使用例でさえもそうではありません。

+0

ありがとう、それは私が今見ているものです。 – jaho

+0

PostEvent – jaho

+0

OKを使用してしまいました。 BTWには、新しいイベント 'wx.lib.newevent'を作成するための便利なモジュールがあります。私はあなたの場合に便利です... – Fenikso

関連する問題