2014-07-11 12 views
0

我正在编程一个GUI软件,它有一个终端窗口(wxCtrl)在执行时实时显示外部程序的输出。pexpect运行长bash命令挂起wxpython GUI

我试过subprocess.Popen,这并不像预期的那样工作,因为它会在运行时挂起我的GUI,并且只在执行完成后给出输出。

def miExecuteCmd(self, cmd): 
    self.terminal.addText("\n###\n\n") 
    self.terminal.addText("Executing: %s\n" % cmd) 
    args = shlex.split(cmd) 
    p = subprocess.Popen(args, stdout = subprocess.PIPE) 
    output = p.stdout.readlines() 
    output = "".join(output) 
    self.terminal.addText(output) 
    if (p.returncode != None and p.returncode != 0): 
     self.terminal.addText("Command Execution Problem, return code is %d\n" % p.returncode) 
    return output 

现在,我尝试使用Pexpect的,我读了这篇文章,how to use pexpect to get spontaneous output of subprocess in python

所以我编码类似,

def miExecuteCmd(self, cmd): 
    self.terminal.addText("\n###\n\n") 
    self.terminal.addText("Executing: %s\n" % cmd) 
    output = [] 
    child = pexpect.spawn(cmd) 
    while True: 
     try: 
      child.expect('\n') 
      line = child.before 
      output.append(line) 
      self.terminal.addText(line) 
     except pexpect.EOF: 
      break 
    if child.exitstatus != None and child.exitstatus != 0: 
     line = "Command Execution Problem, return code is %d\n" % child.exitstatus 
     self.terminal.addText(line) 
     output.append(line) 

    output = "".join(output) 

    return output 

但仍当我用很长的GUI将冻结运行时间cmd。

所以我要求一个简单的pexpect解决方案,允许我操作我的GUI并同时查看cmd的输出。

我看了pexpect文档,看来pexpect.spawn()应该为命令启动一个单独的线程,现在我很困惑是否把pexpect.spawn()放到一个新线程中。

回答

0

最后,我为wxPython中的问题,GUI冻结和线程通信制定了一个很好的解决方案。

应该看过这篇文章http://www.blog.pythonlibrary.org/2010/05/22/wxpython-and-threads,它是一个线程组合,wx.CallAfter(),PubSub来解决线程通信问题。所以在我的情况下,只需添加pexpect以指示要沟通的内容。

这是我的run()例子。您需要在上面的链接中查看示例。

def run(self): 
     wx.CallAfter(self.sendToMainThread, "\n###\n\n") 
     text = "Executing: %s\n" % (self.cmd) 
     wx.CallAfter(self.sendToMainThread, text) 

     child = pexpect.spawn(self.cmd) 
     while True: 
      try: 
       if self.stopFlag: 
        line = "Stop Buttont Clicked, Stopping External Command... \n" 
        wx.CallAfter(self.sendToMainThread, line) 
        child.terminate(True) 
        child.close() 
        break 
       child.expect('\n') 
       line = child.before 
       wx.CallAfter(self.sendToMainThread, line) 
      except pexpect.EOF: 
       child.close() 
       break 
     if child.exitstatus != None and child.exitstatus != 0: 
      line = "Command Execution Problem, return code is %d\n" % child.exitstatus 
      wx.CallAfter(self.sendToMainThread, line) 
     #it looks like next line never happens because of the exception handling above. 
     #child.close() make sure child return a code. 
     elif child.exitstatus == None: 
      line = "Command Execution was interrupted.\n" 
      wx.CallAfter(self.sendToMainThread, line) 

     #sending an end signal to main thread. command is finished. 
     wx.CallAfter(Publisher().sendMessage, "endthread", True) 
1

无论您使用哪种方法执行脚本,您的GUI窗口都会冻结。您需要将这些命令作为单独的线程执行,以便GUI不会被阻止。它会帮助,如果你已经提供代码的一个小例子,但反正尝试这样的事情:

import thread 

def miExecuteCmd(self, cmd): 
    #bunch of codes... 

def on_execute(self, cmd): 
    thread.start_new_thread(self.miExecutecmd,()) 

绑定你的事件处理程序调用self.on_execute这将反过来在一个新的线程执行命令

+0

感谢您的代码,但这并不完整,我需要新的线程来回发送信息给主线程。我在wxpython中使用PubSub计算出它,会很快更新它。 –

+0

如果你之前提到过,我也可以告诉你,以及! – user2963623