从子程序到 pyQT Widget 的标准输出的实时输出
问题描述
您好,我已经看到关于这个问题已经有很多问题了,但是似乎没有一个回答我的问题.
Hi I have seen there are already many questions on this issue however none of them seems to answer my query .
根据下面的链接,我什至在使用 windows 时尝试了 winpexpect,但它似乎对我有用.从 ffmpeg 获取实时输出到用于进度条(PyQt4,stdout)
As per below link i even tried winpexpect as i am using windows , however it dosent seems to e working for me . Getting realtime output from ffmpeg to be used in progress bar (PyQt4, stdout)
我正在使用 subprocess.Popen 运行一个子程序,并希望在 pyQt Widget 中查看实时结果.目前它在 pyQt 小部件中显示结果,但仅在子命令完成执行之后.我需要知道是否有一种方法可以将子进程的输出实时获取到窗口中.请参阅下面的代码,我尝试了所有这些.
I am running a subprogram with subprocess.Popen and want to see the real time result in a pyQt Widget. Currently it shows the result in the pyQt widget but only after the sub command is finished executing . I need to know if there s a way when we can get the output from a subprocess at real time into the window . See the code below which i tried for all this .
import sys
import os
from PyQt4 import QtGui,QtCore
from threading import Thread
import subprocess
#from winpexpect import winspawn
class EmittingStream(QtCore.QObject):
textWritten = QtCore.pyqtSignal(str)
def write(self, text):
self.textWritten.emit(str(text))
class gui(QtGui.QMainWindow):
def __init__(self):
# ...
super(gui, self).__init__()
# Install the custom output stream
sys.stdout = EmittingStream(textWritten=self.normalOutputWritten)
self.initUI()
def normalOutputWritten(self, text):
cursor = self.textEdit.textCursor()
cursor.movePosition(QtGui.QTextCursor.End)
cursor.insertText(text)
self.textEdit.ensureCursorVisible()
def callProgram(self):
command="ping 127.0.0.1"
#winspawn(command)
py=subprocess.Popen(command.split(),stdout=subprocess.PIPE,stderr=subprocess.PIPE,shell=True)
result,_=py.communicate()
for line in result:
print line
print result
def initUI(self):
self.setGeometry(100,100,300,300)
self.show()
self.textEdit=QtGui.QTextEdit(self)
self.textEdit.show()
self.textEdit.setGeometry(20,40,200,200)
print "changing sys.out"
print "hello"
thread = Thread(target = self.callProgram)
thread.start()
#Function Main Start
def main():
app = QtGui.QApplication(sys.argv)
ui=gui()
sys.exit(app.exec_())
#Function Main END
if __name__ == '__main__':
main()
解决方案
QProcess
与 subprocess
非常相似,但在 (Py)Qt 代码中使用更方便.因为它利用信号/插槽.此外,它以异步方式运行进程,因此您无需使用 QThread
.
QProcess
is very similar to subprocess
, but it's much more convenient to use in (Py)Qt code. Because it utilizes signals/slots. Also, it runs the process asynchronously so you don't have use QThread
.
我已经修改(并清理)了您的 QProcess
代码:
I've modified (and cleaned) your code for QProcess
:
import sys
from PyQt4 import QtGui,QtCore
class gui(QtGui.QMainWindow):
def __init__(self):
super(gui, self).__init__()
self.initUI()
def dataReady(self):
cursor = self.output.textCursor()
cursor.movePosition(cursor.End)
cursor.insertText(str(self.process.readAll()))
self.output.ensureCursorVisible()
def callProgram(self):
# run the process
# `start` takes the exec and a list of arguments
self.process.start('ping',['127.0.0.1'])
def initUI(self):
# Layout are better for placing widgets
layout = QtGui.QHBoxLayout()
self.runButton = QtGui.QPushButton('Run')
self.runButton.clicked.connect(self.callProgram)
self.output = QtGui.QTextEdit()
layout.addWidget(self.output)
layout.addWidget(self.runButton)
centralWidget = QtGui.QWidget()
centralWidget.setLayout(layout)
self.setCentralWidget(centralWidget)
# QProcess object for external app
self.process = QtCore.QProcess(self)
# QProcess emits `readyRead` when there is data to be read
self.process.readyRead.connect(self.dataReady)
# Just to prevent accidentally running multiple times
# Disable the button when process starts, and enable it when it finishes
self.process.started.connect(lambda: self.runButton.setEnabled(False))
self.process.finished.connect(lambda: self.runButton.setEnabled(True))
#Function Main Start
def main():
app = QtGui.QApplication(sys.argv)
ui=gui()
ui.show()
sys.exit(app.exec_())
#Function Main END
if __name__ == '__main__':
main()
相关文章