【问题标题】:PyQt5 and subprocess.Popen(...)PyQt5 和 subprocess.Popen(...)
【发布时间】:2019-01-20 13:46:57
【问题描述】:

我有 3 节课

一个是Console 类:

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 类处理)并使用subprocess 运行它。

现在我们遇到了问题:当运行一些不是即时的程序时,整个 GUI 冻结,当Console 类执行 run 函数时,我不知道如何使 GUI 响应.

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

【问题讨论】:

  • 现在我看了一下,它只需要返回self.error,因为它是用来帮助用户找到错误的问题。
  • 当我尝试弄乱信号时,我无法让它工作
  • 首先我在第 556 行将 Console() 分配给 self.Console,然后在第 995 行使用它。
  • 是的,那太棒了!

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


【解决方案1】:

你不使用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_())

【讨论】:

  • subprocess.Popen() 没有阻塞。问题是通信呼叫。虽然可能应该首选 QProcess,但 subprocess.Popen 与 Qt 配合得很好。问题仅在于communicate() 阻塞,直到进程完成。
  • 哇,你重写了两个函数只是为了使用第三方库?
  • 什么,QT 现在是标准库的一部分了吗?对于您的信息,如果存在可以完成这项工作的现有标准库,则切勿使用第三方框架。
  • @eyllanesc 不要喂巨魔:)。好吧,在您的第一句话中,您写道 subprocess.Popen() 是阻塞的,这是不正确的。所以我的评论只是对一个原本完美的答案的小修正。 subprocess.Popen() 不是阻塞的,可以使用,但缺点是计算完成时不会发出信号。所以你必须定期检查它是否还在运行,然后使用process.communicate()。因此,如您所指,首选 QProcess。
【解决方案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())

这是语用学

【讨论】:

  • 什么意思?
  • 改用内置的线程模块,即。 ``导入线程```
  • 在我看来,你来自人类时代。当然我知道 pyqt,几乎构建了我用它构建的所有 UI,仍然用它构建。在Github 上加载我的文件并享受代码。线程模块还有什么用。
  • 这家伙说他有三个课程,我向他展示了如何使用线程模块的详细说明。在上面使用他自己的课程。这只是一个阐述。该代码适用于其他类。除了对已经构建的软件伪装成库的热爱,祝你好运
  • 你知道python吗?线程使用target = function 语法
猜你喜欢
  • 2014-04-23
  • 2011-06-28
  • 2020-04-25
  • 2013-03-09
  • 2018-06-08
  • 2013-08-20
  • 2011-06-16
  • 2018-01-14
相关资源
最近更新 更多