Python 执行包含Linux终端子进程的PyQt5 GUI会导致GUI中出现黑屏并将其冻结

Python 执行包含Linux终端子进程的PyQt5 GUI会导致GUI中出现黑屏并将其冻结,python,linux,terminal,subprocess,pyqt5,Python,Linux,Terminal,Subprocess,Pyqt5,首先,我想向您展示目前为止的工作原理。下面是一个简单的GUI,其原理与导致问题的原理相同。它有一个按钮,当你点击它时,计数器会增加 #!/usr/bin/python3.5 import sys from PyQt5 import QtWidgets class GUI(QtWidgets.QWidget): def __init__(self): QtWidgets.QWidget.__init__(self) self.initGUI()

首先,我想向您展示目前为止的工作原理。下面是一个简单的GUI,其原理与导致问题的原理相同。它有一个按钮,当你点击它时,计数器会增加

#!/usr/bin/python3.5

import sys
from PyQt5 import QtWidgets

class GUI(QtWidgets.QWidget):

    def __init__(self):
        QtWidgets.QWidget.__init__(self)
        self.initGUI()
        self.behaviours()

        self.counter = 0

    def initGUI(self):
        self.button = QtWidgets.QPushButton("Button")
        self.label = QtWidgets.QLabel()

        self.box = QtWidgets.QVBoxLayout()
        self.box.addWidget(self.button)
        self.box.addWidget(self.label)

        self.setLayout(self.box)
        self.show()

    def behaviours(self):
        self.button.clicked.connect(self.add)

    def add(self):
        self.counter = self.counter + 1
        self.label.setText(str(self.counter))

app = QtWidgets.QApplication(sys.argv)
ex = GUI()
sys.exit(app.exec_())
我可以使用以下命令从Linux终端执行脚本:

python3 TestGUI.py
GUI按预期打开,我可以与按钮交互

一旦脚本中包含了一个子流程(如下图所示),GUI仍然会打开,但它完全是黑色的,没有响应

p1 = subprocess.Popen("onedrive", stdout = subprocess.PIPE, shell = True)
(output, err) = p1.communicate()
我认为使用终端执行python脚本时会出现问题,python脚本本身会在终端中执行命令

你知道如何解决这个问题吗


非常感谢您的支持。

您不应该使用Popen,因为该方法是阻塞的,请使用:

#/usr/bin/python3.5
从PyQt5导入QtCore、QtWidgets
类GUI(QtWidgets.QWidget):
def uuu init uuu(self,parent=None):
super()。\uuuu init\uuuu(父级)
self.initGUI()
自我行为
def initGUI(self):
self.button=qtwidts.QPushButton(“按钮”)
self.label=qtwidts.QLabel()
box=qtwidts.QVBoxLayout(self)
box.addWidget(self.button)
box.addWidget(self.label)
self.show()
def行为(自我):
self.\u onedrive\u process=QtCore.QProcess(self)
self.\u onedrive\u process.setProcessChannelMode(QtCore.QProcess.MergedChannels)
self.\u onedrive\u process.readyReadStandardOutput.connect(
self.on_readyReadStandardOutput
)
self.\u onedrive\u process.setProgram(“onedrive”)
self.button.clicked.connect(self.connect\u至\u onedrive)
@QtCore.pyqtSlot()
def连接到onedrive(自):
self.\u onedrive\u process.start()
@QtCore.pyqtSlot()
_readyReadStandardOutput上的def(自):
结果=self.\u onedrive\u process.readAllStandardOutput()
打印(结果)
如果名称=“\uuuuu main\uuuuuuuu”:
导入系统
app=qtwidts.QApplication(sys.argv)
ex=GUI()
sys.exit(app.exec_())
更新:

如果要将选项传递给命令,必须使用:

从PyQt5导入QtCore、QtGui、qtwidget
OneDriveManager类(QtCore.QObject):
logChanged=QtCore.pyqtSignal(str)
def uuu init uuu(self,parent=None):
super()。\uuuu init\uuuu(父级)
self.\u进程=QtCore.QProcess(self)
self.\u process.readyReadStandardOutput.connect(self.on\u readyReadStandardOutput)
self.\u process.setProgram(“onedrive”)
def启动(自身,选项=无):
self.\u进程.设置参数(选项)
if self.\u进程状态()!=QtCore.QProcess.NotRunning:
self.\u进程kill()
self.\u进程启动()
def帮助(自我):
启动([“--help”])
def同步(自):
self.launch([“--synchronize”])
@QtCore.pyqtSlot()
_readyReadStandardOutput上的def(自):
res=self.\u process.readAllStandardOutput().data().decode()
self.logChanged.emit(res)
类小部件(qtwidts.QWidget):
def uuu init uuu(self,parent=None):
super()。\uuuu init\uuuu(父级)
self.\u onedrive\u manager=OneDriveManager(self)
帮助按钮=qtwidts.QPushButton(“帮助”)
帮助按钮。单击。连接(self.\u onedrive\u manager.help)
同步按钮=qtwidts.QPushButton(“同步”)
同步按钮。单击。连接(自。\ onedrive\管理器。同步)
log_plaintextedit=QtWidgets.QPlainTextEdit()
self.\u onedrive\u manager.logChanged.connect(log\u plaintexedit.setPlainText)
lay=qtwidts.QVBoxLayout(self)
lay.addWidget(帮助按钮)
lay.addWidget(同步按钮)
lay.addWidget(日志\u明文编辑)
如果名称=“\uuuuu main\uuuuuuuu”:
导入系统
app=qtwidts.QApplication(sys.argv)
w=Widget()
w、 show()
sys.exit(app.exec_())

在尝试了这一点之后,它成功了,但遗憾的是,还有另一个问题。似乎我无法将命令从“onedrive”扩展到例如“onedrive--synchronize”或“onedrive--help”。尝试此操作时没有打印结果,即使终端中出现一些返回文本。因此,我无法在那里插入更长的命令。经过一点研究,QProcess似乎难以处理更复杂命令的终端语法。有没有一种方法可以执行像“onedrive--synchronize”这样的命令?@PascalAligner我不知道你为什么要指出:经过一点研究,QProcess似乎在更复杂命令的终端语法方面有困难,你能告诉我你过去是怎么得出这个结论的吗?如果你确认了什么,最起码要指出支持你陈述的证据。如果要传递命令选项,必须使用setArguments()或在start:
process.start(“onedrive”,“help”]”)的第二个参数中将其作为列表传递。
,我在回复中添加了一个示例。很抱歉,如果我上面的评论不清楚的话。我发现,使用
setProgram(“onedrive”、[“--help”])
时,我收到了一个错误,即在
setProgram
中使用了太多参数。但正如您所指出的,如果我将这些参数传递给
进程。开始
,就像您在上面的评论中所做的那样,它会起作用。非常感谢您的支持。