PyQt5和subprocess.Popen(...)

时间:2018-08-13 19:01:17

标签: python python-3.x pyqt subprocess pyqt5

我有3个课程

一个是控制台类:

class Console(QWidget):
    def __init__(self):
        super().__init__()
        self.editor = QPlainTextEdit(self)
        self.editor.setReadOnly(True)
        self.font = QFont()
        self.font.setFamily(editor["editorFont"])
        self.font.setPointSize(12)
        self.layout = QVBoxLayout()
        self.layout.addWidget(self.editor, 1)
        self.setLayout(self.layout)
        self.output = None
        self.error = None
        self.editor.setFont(self.font)

    def run(self, command):
        """Executes a system command."""

        out, err = subprocess.Popen(command, shell=True,    stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
        self.output = out
        self.error = err
        self.editor.setPlainText((self.output + self.error).decode())
        return self.output + self.error

另一个是Tabs类,它将Console()赋给变量self.console

然后我有了Main类,它具有一个名为Terminal的功能,可以通过键盘快捷键Shift + F10来调用

这将使用打开的文件的当前文件名(由Tabs类处理),并使用子进程运行它。

现在,当运行一些不是即时的程序时,我们就可以解决问题了,

整个gui死机了,当Console类执行run函数时,我不知道如何使GUI响应

完整代码可在此处找到:https://github.com/Fuchsiaff/PyPad

2 个答案:

答案 0 :(得分:2)

您不使用subprocess.Popen()是因为它正在阻塞,并且阻塞任务的缺点之一是它们不允许GUI执行其他作业,因为此Qt提供了QProcess类不会阻止事件循环:

import sys

from PyQt5 import QtCore, QtGui, QtWidgets

class Console(QtWidgets.QWidget):
    errorSignal = QtCore.pyqtSignal(str) 
    outputSignal = QtCore.pyqtSignal(str)
    def __init__(self):
        super().__init__()
        self.editor = QtWidgets.QPlainTextEdit(self)
        self.editor.setReadOnly(True)
        self.font = QtGui.QFont()
        # self.font.setFamily(editor["editorFont"])
        self.font.setPointSize(12)
        self.layout = QtWidgets.QVBoxLayout()
        self.layout.addWidget(self.editor, 1)
        self.setLayout(self.layout)
        self.output = None
        self.error = None
        self.editor.setFont(self.font)
        self.process = QtCore.QProcess()
        self.process.readyReadStandardError.connect(self.onReadyReadStandardError)
        self.process.readyReadStandardOutput.connect(self.onReadyReadStandardOutput)

    def onReadyReadStandardError(self):
        error = self.process.readAllStandardError().data().decode()
        self.editor.appendPlainText(error)
        self.errorSignal.emit(error)

    def onReadyReadStandardOutput(self):
        result = self.process.readAllStandardOutput().data().decode()
        self.editor.appendPlainText(result)
        self.outputSignal.emit(result)


    def run(self, command):
        """Executes a system command."""
        # clear previous text
        self.editor.clear()
        self.process.start(command)


if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    w = Console()
    w.show()
    w.errorSignal.connect(lambda error: print(error))
    w.outputSignal.connect(lambda output: print(output))
    w.run("ping 8.8.8.8 -c 100")
    sys.exit(app.exec_())

答案 1 :(得分:-2)

使用python的内置线程模块。

然后做:

import threading

用作:

def run(self, command):
    """Executes a system command."""

    tt = threading.Threading( target = self._sub_thread )
    tt.start()

def _sub_thread(self):
    out, err = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE,
                                    stderr=subprocess.PIPE).communicate()
    self.output = out
    self.error = err
    self.editor.setPlainText((self.output + self.error).decode())

这是实用的