我有一个主窗口包装类(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包装器应该与我认为的逻辑分开。
谢谢!
答案 0 :(得分:1)
我认为你可能误解了QProcess
的使用,因为这个例子做了很多奇怪的事情:
selectedNew()
时,它都会创建一个B的新实例,每次都传递相同的QProcess实例。doWork
,它每次都会创建一个本地类定义,只是为了创建一个实例并抛弃该类。该线程在QProcess实例上调用static方法,该实例创建一个可自由运行的新QProcess。doWork
中,您在启动asych线程后立即检查QProcess
的状态,就好像QProcess实例一直发生任何事情一样。主要是,每次都有一个启动 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
进程的信号连接到自己的插槽。然后它用命令的参数调用doWork
。 B
实际上启动了线程并拥有它。