PyQt4 QProcess 状态始终为 0,各种插槽也不起作用 [英] PyQt4 QProcess state always 0, various slots not working too

查看:118
本文介绍了PyQt4 QProcess 状态始终为 0,各种插槽也不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图找出 QProcess (Linux!) 的工作方式,因为我的一个项目将需要它(注意:不使用 suprocess 或多线程!进程也必须与主应用程序分离!).下面是一段演示一些基本功能的小代码:

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()

testCommand.py 如下:

版本 1:

#!/usr/bin/env python

count = 0
while count < 10:
    print "c"
    count = count + 1

版本 2:这里我尝试了一个无限进程来查看 GUI 是否被阻止.

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"

在这里我遇到了多个问题.首先,QProcess.state() 函数总是返回 0,因此我从来没有遇到过 toggleProcess() 函数内的 IF 语句的另外两种情况.由于进程状态没有变化,因此没有任何信号被发出......永远不会.无论我选择我的 testCommand.py 的版本 1,它只运行 10 次循环或版本 2,它无限运行直到进程关闭,结果总是状态 0,即使我可以看到进程正在运行(在版本 2 中,您会得到无限行的c"字符).在我相应地使用版本 2 的情况下,我无法停止进程(因为它的状态不会改变,因此 QProcess.close() 永远不会被调用)所以如果我关闭我的主应用程序,我会创建一个必须通过 htop 或类似进程管理器终止的孤立进程.我知道 QProcess.startDetached() 创建一个分离的进程,但我仍然希望通过开始"按钮对该进程的执行进行一些控制.顺便说一句,当我使用 QProcess.execute() 时,我得到了相同的行为,它创建了一个子进程,并相应地在运行所需的时间内冻结 GUI(在版本 2 中,这是无限期的).

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.

谢谢!

推荐答案

startDetached 函数是静态.分离的进程由 Qt 在内部启动,因此永远不会有一个 QProcess 与之对应.这就是信号不起作用的原因.在您的示例脚本中,myProcess 是完全多余的.

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.

根据定义,分离的进程与启动它的进程没有直接的通信方式.你得到的只是一个pid,就是这样.在某些平台上,可以使用该 pid 来终止进程 - 请参阅 os.kill,例如.

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.

出于与上述相同的原因,无法重新附加到现有流程.您所拥有的只是那个 pid,如果您想稍后重新使用它,则需要以某种方式将其存储在外部(例如在文件中).

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.

广义上讲,您正在处理的问题是进程间通信(IPC).有许多不同的解决方案可用,因此在决定哪一个最合适之前,您需要更清楚地了解应用程序的结构.

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.

这篇关于PyQt4 QProcess 状态始终为 0,各种插槽也不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆