Python 在几个类中使用QProcess的一个实例(PyQt)
我有一个主窗口包装器类(比如a)和包装器中使用的另一个类(比如B)。 B有一个方法,该方法又有一个子进程。check_调用(command)调用。 我将其更改为使用QProcess,以便能够与此进程通信,并在主窗口QTextEdit中显示QProcess stdout和stderr,以及从主窗口QLineEdit将数据发送回QProcess stdin 为此,我有:Python 在几个类中使用QProcess的一个实例(PyQt),python,pyqt4,qprocess,Python,Pyqt4,Qprocess,我有一个主窗口包装器类(比如a)和包装器中使用的另一个类(比如B)。 B有一个方法,该方法又有一个子进程。check_调用(command)调用。 我将其更改为使用QProcess,以便能够与此进程通信,并在主窗口QTextEdit中显示QProcess stdout和stderr,以及从主窗口QLineEdit将数据发送回QProcess stdin 为此,我有: class A(....): def __init__(self): .... QtCore.QOb
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
最后,“在执行期间等待用户输入的脚本”的输出不会显示在QTextEdit中,但仍会打印在控制台中。我似乎没有在A中得到任何信号,也没有到达A.readStdOut()方法。
总体思路是让GUI应用程序包装不同的命令行脚本。因此,我需要一种方法来正确地从QProcess获取输出,并能够通过从GUI写入来进行通信。当然,如果我将函数从B移到A(将消除不必要的步骤),它可能不会那么复杂,但同时我认为GUI包装器应该与逻辑分离
谢谢 我认为您可能误解了使用
QProcess
,因为这个示例做了一些奇怪的事情:
selectedNew()
,它都会创建一个新的B实例,每次都传递相同的QProcess实例doWork
,每次都创建一个本地类定义,只是为了创建一个实例并丢弃该类。线程在QProcess实例上调用staticmethod,该实例创建一个自由运行的新QProcessdoWork
中,您在启动asych线程后立即检查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。这将实际启动进程,并调用您的插槽
我不知道您打算使用classB
做什么,除非您希望将命令行脚本包装到不同的类中,在这种情况下,您将完全将QProcess创建移动到classB
,然后将classA
信号连接到B_实例.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
实际上启动线程并拥有它。非常感谢您详细的回答!我有两个问题:1。B类是一个包装一些与基础设施相关的设置步骤的程序。它是一个接受用户输入的脚本,通过调用子流程(即执行不同的脚本和程序)执行多个不同的任务。现在,用户输入被gui替换为我的脚本,但是底层的用户仍然期望一些用户交互。我不想把所有的B功能都转移到A类中。2.您能告诉我如何将A signals连接到B_instance.qprocess以能够对其进行读/写吗?刚刚添加了另一个示例,说明如何将流程功能下移到B
,再次感谢您提供的精彩信息-它几乎可以工作了!有一件事:在类B中启动进程后,我说self.qprocess.waitForFinished(),以便让底层程序完成所有的任务,这样我的脚本就可以继续了。当底层脚本要求用户确认继续时,我得到完成的信号!我希望能够启动基础脚本,当它要求确认时,我希望能够回答,以便它可以继续或取消。(基础脚本不是我的-无法编辑)。不过,它似乎只是在计时……首先,如果调用waitForFinished
,它将在主线程中阻止整个应用程序。首先,您计划如何与流程进行沟通?您的主UI元素是否正在读取标准输出,然后您有其他一些将写入进程的行编辑输入?你不能等待这个过程。您需要使用信号和输出读数。然后,您可以在进程上调用writeData()
,以发回用户输入。