wxPython + подпроцесс.ProgressDialog не работает под окнами - PullRequest
1 голос
/ 24 октября 2011

У меня есть приложение с графическим интерфейсом, которое запускает некоторые команды, используя подпроцесс, а затем показывает ход выполнения этих команд, читая из subprocess.Popen.stdout и используя wx.ProgressDialog. Я написал приложение под Linux, и оно там работает без нареканий, но сейчас я провожу некоторое тестирование под 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, просто индикатор прогресса не двигается Чего мне не хватает?

1 Ответ

0 голосов
/ 24 октября 2011

Попробуйте не использовать wx.MutexGuiEnter и wx.MutexGuiLeave.Вы можете выполнить обновление графического интерфейса из другого потока, используя wx.CallAfter.Я никогда раньше не видел, чтобы кто-либо использовал эти мьютексы в приложении wx, и даже в учебниках или примерах использования потоков.

...