在几个类中使用1个QProcess实例(PyQt)

时间:2012-08-23 21:03:16

标签: python pyqt4 qprocess

我有一个主窗口包装类(Say A)和另一个在包装器中使用的类(比如说B)。 B有一个方法,然后HAD一个subrocess.check_call(命令)调用。 我正在改变它以使用QProcess以便能够与此进程通信并在主窗口QTextEdit中显示Qprocess stdout和stderr以及从主窗口QLineEdit将数据发送回Qprocess stdin。

为此我有:

class A(....):
   def __init__(self):
      ....
      QtCore.QObject.connect(self.ui.actionNew, QtCore.SIGNAL("triggered()", self.selectedNew)
      self.qprocess = QtCore.QProcess()
      self.connect(self.qprocess, QtCore.SIGNAL("readyReadStandardOutput()", self.readStdOut)
      self.connect(self.qprocess, QtCore.SIGNAL("readyReadStandardError()", self.readStdErr)

    def readStdOut(self):
        self.ui.text_edit.append(QtCore.QString(self.qprocess.readAllStandardOutput()))

    def readStdErr(self):
        self.ui.text_edit.append(QtCore.QString(self.qprocess.readAllStandardError()))

    def selectedNew(self:)
        ...
        newB = B(self.qprocess)
        newB.doWork(params)

 class B():
     def __init__(self, qprocess):
         self.qp = qprocess

     def doWork(params):
         ...
         # creating a thread to not block the main thread
         class ConsoleThread(threading.Thread):

             def __init__(self, qprocess):
                self.tqp = qprocess
                threading.Thread.__init__(self)

             def run(self):
                 self.qtp.execute("script_that_waits_for_user_input_during_execution")

          # starting the thread and passing it the QProcess instance from B
          ConsoleThread(self.qp).start()
          print(self.qp.state()) # this returns 0, when I expected 2, obviously something wrong

最后,“script_that_waits_for_user_input_during_execution”的输出未显示在QTextEdit中,但仍在控制台中打印。我似乎没有在A中得到任何信号而我没有达到A.readStdOut()方法。 一般的想法是让GUI应用程序包装不同的命令行脚本。所以我需要一种方法来正确地从QProcess获取输出,并能够通过从GUI写入来进行通信。当然,如果我将函数从B移动到A(将消除不必要的步骤),它可能会变得不那么复杂,但同时GUI包装器应该与我认为的逻辑分开。

谢谢!

1 个答案:

答案 0 :(得分:1)

我认为你可能误解了QProcess的使用,因为这个例子做了很多奇怪的事情:

  1. A类的实例获得作为成员创建的QProcess,并且连接信号
  2. 每次调用selectedNew()时,它都会创建一个B的新实例,每次都传递相同的QProcess实例。
  3. 然后调用
  4. doWork,它每次都会创建一个本地类定义,只是为了创建一个实例并抛弃该类。该线程在QProcess实例上调用static方法,该实例创建一个可自由运行的新QProcess。
  5. doWork中,您在启动asych线程后立即检查QProcess的状态,就好像QProcess实例一直发生任何事情一样。
  6. 主要是,每次都有一个启动 new 进程的线程,然后检查原始版本上没有更改的值,因为它从未启动过。信号永远不会被调用,因为它们与原始过程相关联。为了简化整个情况,每次要运行时,只需要一个新的QProcess。

    首先,让我们将该类A清理成能够正常工作的内容:

    class A():
        def __init__(self):
          ...
          self.ui.actionNew.triggered.connect(self.selectedNew)
    
        def readStdOut(self):
            self.ui.text_edit.append(str(self.qprocess.readAllStandardOutput()))
    
        def readStdErr(self):
            self.ui.text_edit.append(str(self.qprocess.readAllStandardError()))
    
        def selectedNew(self):
            ...
            qprocess = QtCore.QProcess(self)
            qprocess.readyReadStandardOutput.connect(self.readStdOut)
            qprocess.readyReadStandardError.connect(self.readStdErr)
    
            qprocess.start("script_that_waits_for_user_input", params)
    
            print qprocess.state() == qprocess.Running
    

    不是在init中创建QProcess,而是在想要运行某些东西时按需创建它。您将该实例的信号连接到您的插槽,并在QProcess上调用start。这实际上将启动该过程,并调用您的插槽。

    我不知道您打算使用类B,除非您想将命令行脚本包装到不同的类中,在这种情况下,您将完全将QProcess创建移动到类B ,然后将您的班级A信号连接到b_instance.qprocess成员。

    <强>更新

    为了将此QProcess责任下移到B类,以便您可以使用许多不同的类类型来执行不同类型的工作,它可能如下所示:

    class A(QtGui.QMainWindow):
        ...
    
        def readStdOut(self):
            qprocess = self.sender()
            self.ui.text_edit.append(QtCore.QString(qprocess.readAllStandardOutput()))
    
        def readStdErr(self):
            qprocess = self.sender()
            self.ui.text_edit.append(QtCore.QString(qprocess.readAllStandardError()))
    
    
        def selectedNew(self):
            ...
            b = B()
            b.qprocess.readyReadStandardOutput.connect(self.readStdOut)
            b.qprocess.readyReadStandardError.connect(self.readStdErr)
    
            b.doWork(params)
    
            print b.qprocess.state() == qprocess.Running
    
    
    class B(QtCore.QObject):
        def __init__(self):
            ...
            self.qprocess = QtCore.QProcess(self)
    
        def doWork(params):
            ...
            self.qprocess.start("script_that_waits_for_user_input", params)
    

    A创建B的新实例,并将B进程的信号连接到自己的插槽。然后它用命令的参数调用doWorkB实际上启动了线程并拥有它。