【发布时间】:2023-07-03 06:01:01
【问题描述】:
我正在尝试弄清楚 QProcess (Linux!) 的工作方式,因为我的项目需要它(注意:不使用 suprocess 或多线程!进程也必须与主应用程序分离!)。这是一个小代码来演示一些基本功能:
#!/usr/bin/python
import sys
from PyQt4 import QtGui, QtCore
from PyQt4.QtCore import QProcess
class Example(QtGui.QWidget):
def __init__(self):
super(Example, self).__init__()
self.myProcess = QProcess(self)
self.myProcess.finished.connect(self.onFinished) # NEVER called
self.myProcess.stateChanged.connect(self.onStateChanged) # NEVER called
self.myProcess.started.connect(self.onStarted) # NEVER called
self.command = "./testCommand.py"
self.args = [""]
self.initUI()
def initUI(self):
hbox = QtGui.QHBoxLayout()
hbox.addStretch(1)
qbtn = QtGui.QPushButton('Start', self)
qbtn.clicked.connect(self.toggleProcess)
qbtn.resize(qbtn.sizeHint())
hbox.addWidget(qbtn)
# This button is for testing the responsiveness of the GUI after the QProcess has been started
qbtn2 = QtGui.QPushButton('Click me', self)
qbtn2.setCheckable(True)
qbtn2.toggled.connect(self.toggleButton)
qbtn2.resize(qbtn2.sizeHint())
hbox.addWidget(qbtn2)
self.setLayout(hbox)
self.setGeometry(300, 300, 250, 150)
self.setWindowTitle('QProcess controlled by a button')
self.show()
def toggleProcess(self):
# process states (based on Qt docs):
# 0 - not running
# 1 - starting
# 2 - running
# For some reason state is ALWAYS 0
if self.myProcess.state() == 0:
self.myProcess.startDetached(self.command, self.args)
print "Starting process"
print "Process state", str(self.myProcess.state())
elif self.myProcess.state() == 1:
print "Process is starting"
return
else:
print "Stopping process"
self.myProcess.close()
def toggleButton(self, value):
if value == True:
print "Lalalala!"
else:
print "Didadida!"
def onStarted(self):
print "Process started"
def onFinished(self):
print "Process stopped"
def onStateChanged(self):
print "Process has changed state"
def __del__(self):
if self.myProcess.state() == 1 or self.myProcess.state() == 2:
self.myProcess.close()
else:
pass
def main():
app = QtGui.QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
testCommand.py如下:
版本 1:
#!/usr/bin/env python
count = 0
while count < 10:
print "c"
count = count + 1
VERSION 2:这里我尝试了一个无限进程来查看 GUI 是否被阻塞。
#!/usr/bin/env python
while True:
print "c"
在这里我遇到了多个问题。首先,QProcess.state() 函数总是返回 0,因此我永远不会在 toggleProcess() 函数中遇到我的 IF 语句的其他两种情况。由于进程状态没有变化,因此没有任何信号被发出……永远。无论我选择我的 testCommand.py 的版本 1,它只运行一个循环 10 次或版本 2,它无限运行直到进程关闭,结果总是状态 0,即使我可以看到该进程正在运行(在版本 2 中,您将获得无限行的“c”字符)。在我相应地使用 VERSION 2 的情况下,我无法停止进程(因为它的状态不会改变,因此永远不会调用 QProcess.close())所以如果我关闭我的主应用程序,我会创建一个必须通过 htop 或类似进程管理器杀死的孤立进程。我知道 QProcess.startDetached() 创建了一个分离的进程,但我仍然希望通过“开始”按钮对该进程的执行进行一些控制。顺便说一句,当我使用 QProcess.execute() 时,我得到了相同的行为,它创建了一个子进程并相应地冻结了 GUI 运行所需的时间(在版本 2 中这是无限期的)。
谁能告诉我为什么会这样?我想要的只是能够启动一个分离的进程,但仍然能够通过同一个按钮终止它。我也尝试过使用可检查按钮(例如“单击我”按钮)和布尔标志,但缺少状态更改的问题仍然存在。
谢谢!
【问题讨论】:
-
显然这是
startDetached()的预期行为,请参阅this question 等。如果你想使用QProcess的信号,你必须使用start() -
是的,我已经看到了这个问题,但是我未来的目标是创建一个 GUI 防崩溃进程管理器(我正在使用 ROS),即使 GUI 崩溃,启动的进程也会继续存在并且一旦 GUI 重新启动,它将使用存储在某个文件中的 PID 重新连接到这些进程。所以这里的 GUI 只是控制多个 QProcess-es 的一种便捷方式,仅此而已。这就是为什么 startDetached() 是我唯一的选择,因为如果我的 GUI 终止,start() 将导致创建的进程也终止。
标签: python qt pyqt pyqt4 qprocess