You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PySide2关闭时终止QProcess问题:如何实现PyQt4同款子进程保留行为?

PySide2 QProcess子进程随主程序关闭的问题解决

我之前用PyQt4写了个测试程序,在Linux上用QProcess启动外部程序并捕获它的标准输出。关闭主应用后,子进程还能继续跑,这正是我想要的效果。但把代码改成PySide2版本(切换到QtWidgets这些模块)之后,关闭主应用时子进程也跟着退出了。我想知道这是PyQt4或者PySide2的Bug吗?有没有办法让PySide2实现和PyQt4一样的行为?另外我知道startDetached方法,但用它就没法获取标准输出了,所以这个方案行不通。

附原PySide2示例代码:

import sys
from PySide2 import QtWidgets,QtCore, QtWidgets
class gui(QtWidgets.QMainWindow):
    def __init__(self):
        super(gui, self).__init__()
        self.initUI()
    def stdoutReady(self, process):
        data = str(self.process.readAllStandardOutput())
        print('STDOUT: {}'.format(data))
    def stderrorReady(self, process):
        data = str(self.process.readAllStandardError())
        print('STDERROR: {}'.format(data))
    def processFinished(self, exitCode, exitStatus):
        print('EXIT CODE: {}, EXIT STATUS: {}'.format(exitCode, exitStatus))
    def initUI(self):
        layout = QtWidgets.QHBoxLayout()
        centralWidget = QtWidgets.QWidget()
        centralWidget.setLayout(layout)
        self.setCentralWidget(centralWidget)
        self.process = QtCore.QProcess(self)
        self.process.readyReadStandardOutput.connect(lambda: self.stdoutReady(self.process))
        self.process.readyReadStandardError.connect(lambda: self.stderrorReady(self.process))
        self.process.start('dolphin')
def main():
    app = QtWidgets.QApplication(sys.argv)
    ui=gui()
    ui.show()
    sys.exit(app.exec_())
if __name__ == '__main__':
    main()

这不是Bug,是默认行为差异!

PyQt4和PySide2在QProcess的父对象处理逻辑上默认不一样:

  • 在PyQt4中,即使给QProcess设置了父对象(比如代码里的QProcess(self)),主进程退出时也不会自动终止子进程;
  • 但PySide2中,当QProcess的父对象(这里是主窗口)被销毁时,会自动触发子进程的终止操作,导致子进程跟着退出。

解决方案:两种方法实现PyQt4相同行为

你不需要用startDetached,可以通过以下两种方式保留标准输出捕获的同时,让子进程在主应用关闭后继续运行:

方法1:不给QProcess设置父对象

创建QProcess时不要传入self作为父参数,这样它就不属于主窗口的对象树,主窗口销毁时不会触发它的终止逻辑:

self.process = QtCore.QProcess()

方法2:保留父对象,设置DetachOnExit属性

如果必须给QProcess设置父对象,可以手动开启DetachOnExit属性,告诉Qt在主进程退出时分离子进程:

self.process = QtCore.QProcess(self)
self.process.setProcessAttribute(QtCore.QProcess.DetachOnExit, True)

修改后的完整示例代码

这里还优化了一下标准输出的编码处理,避免出现不必要的字符:

import sys
from PySide2 import QtWidgets, QtCore

class gui(QtWidgets.QMainWindow):
    def __init__(self):
        super(gui, self).__init__()
        self.initUI()

    def stdoutReady(self):
        # 处理编码,避免乱码和多余的转义字符
        data = str(self.process.readAllStandardOutput(), encoding='utf-8').strip()
        print('STDOUT: {}'.format(data))

    def stderrorReady(self):
        data = str(self.process.readAllStandardError(), encoding='utf-8').strip()
        print('STDERROR: {}'.format(data))

    def processFinished(self, exitCode, exitStatus):
        print('EXIT CODE: {}, EXIT STATUS: {}'.format(exitCode, exitStatus))

    def initUI(self):
        layout = QtWidgets.QHBoxLayout()
        centralWidget = QtWidgets.QWidget()
        centralWidget.setLayout(layout)
        self.setCentralWidget(centralWidget)
        
        # 选其中一种方案即可
        # 方案1:无父对象
        self.process = QtCore.QProcess()
        
        # 方案2:带父对象并设置DetachOnExit
        # self.process = QtCore.QProcess(self)
        # self.process.setProcessAttribute(QtCore.QProcess.DetachOnExit, True)
        
        # 连接信号,去掉多余的lambda表达式
        self.process.readyReadStandardOutput.connect(self.stdoutReady)
        self.process.readyReadStandardError.connect(self.stderrorReady)
        self.process.finished.connect(self.processFinished)
        
        self.process.start('dolphin')

def main():
    app = QtWidgets.QApplication(sys.argv)
    ui = gui()
    ui.show()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()

这样修改后,你关闭PySide2主应用时,dolphin进程会继续运行,同时你依然能正常捕获它的标准输出和错误输出,完全符合你的需求。

内容的提问来源于stack exchange,提问作者Michael B

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 09:16:38