PyQt5 和 subprocess.Popen(...) [英] PyQt5 and subprocess.Popen(...)

查看:39
本文介绍了PyQt5 和 subprocess.Popen(...)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有 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

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

The other one is a Tabs class which assings Console() to the variable self.console

然后我有一个 Main 类,它有一个名为 Terminal 的函数,可以通过键盘快捷键 Shift+F10 调用

And then I have the Main class which has a function called Terminal which can be called by a keyboard shortcut Shift+F10

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

That will take the current filename of the file opened (this is handled with the Tabs class) and run it using subprocess.

现在我们来解决这个问题,当运行一些不是即时的程序时,

Now we get to the problem, when running some programs that aren't instant,

整个 gui 冻结,当 Console 类执行了 run 函数时,我无法弄清楚如何使 GUI 响应

the whole gui freezes and I can't figure out how to make the GUI responsive when the Console class has executed the run function

完整代码可以在这里找到:https://github.com/Fuchsiaff/PyPad

The whole code can be found here: https://github.com/Fuchsiaff/PyPad

推荐答案

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

You do not use subprocess.Popen() because it is blocking, and just one of the disadvantages of blocking tasks is that they do not allow the GUI to perform other jobs, for this Qt provides the QProcess class that does not block the event-loop:

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_())

这篇关于PyQt5 和 subprocess.Popen(...)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆