以下是代码示例:
class RunGui (QtGui.QMainWindow)
def __init__(self, parent=None):
...
QtCore.Qobject.connect(self.ui.actionNew, QtCore.SIGNAL("triggered()"), self.new_select)
...
def normal_output_written(self, qprocess):
self.ui.text_edit.append("caught outputReady signal") #works
self.ui.text_edit.append(str(qprocess.readAllStandardOutput())) # doesn't work
def new_select(self):
...
dialog_np = NewProjectDialog()
dialog_np.exec_()
if dialog_np.is_OK:
section = dialog_np.get_section()
project = dialog_np.get_project()
...
np = NewProject()
np.outputReady.connect(lambda: self.normal_output_written(np.qprocess))
np.errorReady.connect(lambda: self.error_output_written(np.qprocess))
np.inputNeeded.connect(lambda: self.input_from_line_edit(np.qprocess))
np.params = partial(np.create_new_project, section, project, otherargs)
np.start()
class NewProject(QtCore.QThread):
outputReady = QtCore.pyqtSignal(object)
errorReady = QtCore.pyqtSignal(object)
inputNeeded = QtCore.pyqtSignal(object)
params = None
message = ""
def __init__(self):
super(NewProject, self).__init__()
self.qprocess = QtCore.QProcess()
self.qprocess.moveToThread(self)
self._inputQueue = Queue()
def run(self):
self.params()
def create_new_project(self, section, project, otherargs):
...
# PyDev for some reason skips the breakpoints inside the thread
self.qprocess.start(command)
self.qprocess.waitForReadyRead()
self.outputReady.emit(self.qprocess) # works - I'm getting signal in RunGui.normal_output_written()
print(str(self.qprocess.readAllStandardOutput())) # prints empty line
.... # other actions inside the method requiring "command" to finish properly.
这个想法被打败了 - 获取GUI来运行脚本并与进程通信。此特定示例中的挑战是脚本在QProcess中启动,因为命令运行应用程序,需要用户输入(确认)。因此,我必须能够启动脚本,获取所有输出并解析它,等待问题出现在输出中,然后回复答案,允许它完成,然后再继续进行create_new_project内的其他操作( )
答案 0 :(得分:1)
我不知道这是否能解决您的整体问题,但我在这里看到一些设计问题。
从技术上讲,您甚至不需要QProcess,因为您在线程中运行它并主动使用阻塞调用。它可能很容易成为一个子进程.Popen ......但无论如何,我可能会建议这样的改变:
class RunGui (QtGui.QMainWindow)
...
def normal_output_written(self, msg):
self.ui.text_edit.append(msg)
def new_select(self):
...
np = NewProject()
np.outputReady.connect(self.normal_output_written)
np.params = partial(np.create_new_project, section, project, otherargs)
np.start()
class NewProject(QtCore.QThread):
outputReady = QtCore.pyqtSignal(object)
errorReady = QtCore.pyqtSignal(object)
inputNeeded = QtCore.pyqtSignal(object)
def __init__(self):
super(NewProject, self).__init__()
self._inputQueue = Queue()
self.params = None
def run(self):
self.params()
def create_new_project(self, section, project, otherargs):
...
qprocess = QtCore.QProcess()
qprocess.start(command)
if not qprocess.waitForStarted():
# handle a failed command here
return
if not qprocess.waitForReadyRead():
# handle a timeout or error here
return
msg = str(self.qprocess.readAllStandardOutput())
self.outputReady.emit(msg)
不要绕过QProcess。只是发出数据。并在threads方法中创建它,以便它由该线程自动拥有。你的外部类应该对该QProcess对象一无所知。它甚至不需要是成员属性,因为它只在操作期间需要。
还要确保您正确检查您的命令是否已成功启动,并且正在运行并输出数据。
为了澄清您可能遇到的一些问题(根据评论),我想建议如果您需要对期望定期用户输入的流程进行交互式控制,QProcess可能不是最佳选择。它应该可以找到运行从头到尾生成输出的脚本,但真正使用子进程会更容易。对于需要用户输入的脚本,最好的选择可能是使用pexpect
。它允许您生成一个进程,然后观察您知道将表明需要输入的各种模式:
<强> foo.py 强>
import time
i = raw_input("Please enter something: ")
print "Output:", i
time.sleep(.1)
print "Another line"
time.sleep(.1)
print "Done"
<强> test.py 强>
import pexpect
import time
child = pexpect.spawn("python foo.py")
child.setecho(False)
ret = -1
while ret < 0:
time.sleep(.05)
ret = child.expect("Please enter something: ")
child.sendline('FOO')
while True:
line = child.readline()
if not line:
break
print line.strip()
# Output: FOO
# Another line
# Done