【问题标题】:wxPython + subprocess. ProgressDialog doesn't work under windowswxPython + 子进程。 ProgressDialog 在 windows 下不起作用
【发布时间】:2011-12-14 01:15:06
【问题描述】:

我有一个 GUI 应用程序,它使用子进程启动一些命令,然后通过从 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,只是进度条不动。我错过了什么?

【问题讨论】:

  • 如果您能将问题缩小到非常小的可运行应用程序,我们可以在我们的计算机上实际试用,那就太好了。
  • 如果我找不到解决方案,我稍后会尝试这样做,但是您可能需要一些简单的 C 应用程序来测试它。我在子进程中执行的命令已被修改以避免任何缓冲,因此 proc.stdout.readline() 在生成后立即获取输出。否则,在命令完成之前输出不可用,因为 C 标准输出实现在写入管道时使用完全缓冲。这可以在 linux 上使用“unbuffer”解决,但在 windows 上需要对 C 代码进行一些修改。如果我无法使用 wx.CallAfter 解决问题,我会稍后再回来。

标签: windows multithreading user-interface wxpython subprocess


【解决方案1】:

尽量不要使用wx.MutexGuiEnterwx.MutexGuiLeave。您可以使用 wx.CallAfter 从另一个线程更新 GUI。我之前从未见过有人在 wx 应用程序中使用过这些互斥锁,甚至在教程或使用线程的示例中也没有。

【讨论】:

  • 谢谢,这是我目前正在研究的问题。
  • 好的。顺便说一句,有用于创建新事件的便捷模块wx.lib.newevent。在你的情况下我会很方便......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-06-19
  • 1970-01-01
  • 2016-01-03
  • 1970-01-01
  • 2013-10-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多