问题
I am trying to figure out the way QProcess (Linux!) works because I'm going to need it for a project of mine (Note: suprocess or multithreading is not to be used! The process also has to be detached from the main application!). Here is a small code to demonstrate some basic functionality:
#!/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()
The testCommand.py is as follows:
VERSION 1:
#!/usr/bin/env python
count = 0
while count < 10:
print "c"
count = count + 1
VERSION 2: Here I try an infinite process to see if the GUI is blocked or not.
#!/usr/bin/env python
while True:
print "c"
Here I've encountered multiple issues. First of all the QProcess.state() function always returns 0 hence I never land in the two other cases of my IF statement inside the toggleProcess() function. Because of this absence of change in the process' state none of the signals gets emitted...ever. No matter if I pick the VERSION 1 of my testCommand.py, which runs a loop just 10 times or VERSION 2, which runs infinitely till the process is closed, the result is always state 0 even though I can SEE that the process is running (in VERSION 2 you get infinite lines of "c" characters). In the case I use VERSION 2 accordingly I am unable to stop the process (because its state does not change hence the QProcess.close() is never called) so if I close my main application I create an orphaned process that has to be killed via htop or similar process manager. I know that QProcess.startDetached() creates a detached process but I still hope to have some control over the execution of that process via the "Start" button. Btw same behaviour I get when I use QProcess.execute(), which creates a sub-process and accordingly freezes the GUI for the time that it requires to run (in VERSION 2 this is indefinitely).
Can anyone tell me why this is happening? All I want is to be able to start a detached process but still be able to terminate it via the same button. I have also tried with a checkable button (like for the "Click me" button) and also with a boolean flag, but the issue with the missing change of state is still there.
Thanks!
回答1:
The startDetached function is static. The detached process is started internally by Qt, and so there is never a QProcess
that corresponds to it. That is why the signals will not work. In your example script, myProcess
is completely redundant.
By definition, a detached process has no direct means of communication with the process that started it. All you get is a pid, and that's it. On some platforms it may be possible to use that pid to kill the process - see os.kill, for instance.
For the same reasons as above, there is no way to re-attach to an existing process. All you have is that pid, which will need to be stored externally somehow (e.g. in a file) if you want to re-use it later.
Broadly speaking, the problem you are dealing with is Inter-process communication (IPC). There are many different solutions available, so you will need to get a much clearer idea of the structure of your application before deciding which one is most appropriate.
来源:https://stackoverflow.com/questions/31455075/pyqt4-qprocess-state-always-0-various-slots-not-working-too