0

我有一个主窗口包装类(比如 A)和包装中使用的另一个类(比如 B)。B 有一个方法,该方法反过来有一个 subprocess.check_call(command) 调用。我将其更改为使用 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 包装器应该与我认为的逻辑分开。

谢谢!

4

1 回答 1

1

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

  1. 类 A 的一个实例获得一个创建为成员的 QProcess,并发出连接的信号
  2. 每次selectedNew()调用时,它都会创建一个 B 的新实例,每次都传递相同的 QProcess 实例。
  3. doWork然后调用它,它每次都会创建一个本地类定义,只是为了创建一个实例并丢弃该类。该线程在 QProcess 实例上调用一个静态方法,该方法创建一个可以自由运行的新 QProcess。
  4. doWork中,您在启动 asych 线程后立即检查QProcess右侧的状态,就好像 QProcess 实例一直发生任何事情一样。

主要是,您有一个线程每次都启动一个进程,然后您检查一个不会更改原始值的值,因为它从未启动过。并且信号永远不会被调用,因为它们附加到那个原始过程。为了简化整个情况,您只需在每次要运行时创建一个新的 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。这实际上将启动该过程,并调用您的插槽。

我不知道您打算使用 class 做什么B,除非您想将命令行脚本包装到不同的类中,在这种情况下,您会将 QProcess 创建完全移至 class 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的进程的信号连接到它自己的槽。然后它doWork使用命令的参数调用 。B实际上启动线程并拥有它。

于 2012-08-23T23:47:23.870 回答