使用QThread
来避免UI冻结; 在线程中运行脚本使用subprocess.Popen
与stdout=PIPE
, 逐行读取它们的输出,emit
的行,并得到他们在任何slot
你想要的。
from PyQt4.QtGui import QTextBrowser, QApplication
from PyQt4.QtCore import pyqtSignal, QThread
from subprocess import Popen, PIPE
from Queue import Queue
from threading import Event
class ScriptRunner(QThread):
# fired whenever a line from subprocess.stdout arrived
got_line = pyqtSignal(unicode)
def __init__(self):
QThread.__init__(self)
self.queue = Queue()
self.put = self.queue.put
self.stop_event = Event()
self.start()
def run(self):
"""thread function"""
while 1:
script = self.queue.get()
if script is None: # no more scripts
break
# run the script
proc = Popen(script, bufsize=1, stdout=PIPE, shell=True,
universal_newlines=True)
# read its output line by line
while not self.stop_event.is_set():
line = proc.stdout.readline()
if not line:
break
self.got_line.emit(line)
def join(self):
self.stop_event.set()
self.put(None)
self.wait()
if __name__ == '__main__':
app = QApplication([])
text_browser = QTextBrowser()
text_browser.show()
runner = ScriptRunner()
# connect to got_line signal
runner.got_line.connect(text_browser.insertPlainText)
# schedule a script
runner.put('''python -c "for i in range(25): print 'dada'; import time; time.sleep(.25)"''')
# now force python to flush its stdout; note -u switch
runner.put('''python -uc "for i in range(25): print 'haha'; import time; time.sleep(.25)"''')
app.exec_()
runner.join()
不过请注意,由于缓冲脚本的输出可能会在大块, 使其难以实现实时平滑像终端。 使用python,你可以通过将-u
切换到解释器(而不是脚本)来规避这种情况。