1

我有一個GUI應用程序,它使用子進程啓動一些命令,然後通過從subprocess.Popen.stdout中讀取並使用wx.ProgressDialog來顯示此命令的進度。我已經在Linux下編寫了該應用程序,它在那裏完美地工作,但我現在正在Windows下進行一些測試,似乎試圖更新進度對話框會導致應用程序掛起。沒有錯誤信息或任何內容,所以我很難弄清楚發生了什麼。下面是一個簡單的代碼:wxPython +子流程。 ProgressDialog無法在windows下工作

子進程在單獨的線程用這種方法在主線程啓動:

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

好的。順便說一句,有創建新事件'wx.lib.newevent'的便利模塊。我的方式在你的情況下... – Fenikso