PyQt中QProcess失败的原因

时间:2017-02-12 07:21:48

标签: pyqt openocd

我正在编写一个使用openOCD的GUI。代码片段应该启动openOCD服务器并在textEdit小部件上显示它的输出。 但是,虽然我没有看到任何错误消息,但该过程无法按预期工作。我检查了ps -aux,它将openOCD进程显示为已失效。 进程状态为“1”,根据文档表示进程崩溃。我哪里错了?

class BadgeMain(Ui_MainWindow):
        def __init__(self,dialog,parent=None):
                Ui_MainWindow.__init__(self)
                self.setupUi(dialog)
                self.pushButton_JtagStartServer.clicked.connect(self.JTAG_startserver)
                self.JTAG_ServerProcess = QtCore.QProcess()
                self.JTAG_ServerProcess.readyRead.connect(self.JTAG_dataReady)


        def JTAG_dataReady(self):
                cursor=self.textEdit_JtagConsole.textCursor()
                cursor.movePosition(cursor.End)
                cursor.insertText(str(self.Jtag_process.readAll()))
                self.textEdit_JtagConsole.ensureCursorVisible()

        def JTAG_startserver(self):
                self.JTAG_ServerProcess.start('openocd',['-c','telnet_port 4444','-f','cfg/ftdi.cfg','-f','cfg/stm32.cfg'])
                print(str(self.JTAG_ServerProcess.state()))

1 个答案:

答案 0 :(得分:0)

未经测试,但我之前已经包装了QProcess,因此我可以在错误时获得更多信息 请参见errorText()方法:

class Process(QtCore.QProcess):
    """
    Makes QProcess a bit more usable (to my mind) in the following ways:
    - Automatically frees memory when it's spent (see __singleshot).
    - Makes stderr and stdout more-like 'properties' of the object, rather than weird streams/buffers that evaporate after you read them!
    - Abstracts success & failure such that succeeded() means 'everything succeeded' and failed() to mean '*something* failed'.
    - All error text is available from a single call, regardless of error-origin (QProcess; the program invoked; or the underlying device).
    - Defines __finished to mean 'we either succeeded or failed but, either way, it's all over'.
    - Added various helper methods such as isValid(), isRunning(), etc.
    """
    def __init__(self, singleshot=True, *args, **kwargs):
        super().__init__(*args, **kwargs)

        # Important that these slots are connected first, so our responses are readied first.
        self.finished.connect(self.on_finished)
        self.error.connect(self.on_error)

        self.__singleshot = singleshot

        self.__finished = False
        self.__stdoutText = ""
        self.__stderrText = ""
        self.__QProcessErrorText = ""
        self.__QIODeviceErrorText = ""
        self.__QIODeviceDefaultErrorString = self.errorString()  # So we can later avoid QIODevice's pessimistic, spurious default message of 'Unknown Error'.
        self.__succeeded = False

    def on_error(self, error):
        self.__finished = True
        self.__succeeded = False   # .. probably overkill.. (probably already False..)
        errorMap = {self.FailedToStart:    "The process failed to start.",
                    self.Crashed:          "The process crashed some time after starting successfully.",
                    self.Timedout:         "The last waitFor...() function timed out.",
                    self.WriteError:       "An error occurred when attempting to write to the process.",
                    self.ReadError:        "An error occurred when attempting to read from the process.",
                    self.UnknownError:     "An unknown error occurred."}
        self.__QProcessErrorText = errorMap[error]
        if self.__singleshot: self.deleteLater()   ## Kinda handy for memory-management...

    def on_finished(self, exitCode, exitStatus):
        self.__finished = True
        self.__succeeded = (exitCode == 0) & (exitStatus == self.NormalExit)
        if self.__singleshot: self.deleteLater()   ## Kinda handy for memory-management...

    def outputText(self):
        # Drain the stdout buffer into local instance variable..
        self.__stdoutText += str(self.readAllStandardOutput(), encoding='utf-8')
        return self.__stdoutText

    def stdErrText(self):
        # Drain the stderr buffer into local instance variable..
        self.__stderrText += str(self.readAllStandardError(), encoding='utf-8')
        return self.__stderrText

    def errorText(self, delimiter=".  "):
        # Returns string detailing error from any potential error source (the program; the QProcess; the underlying QIODevice).
        errorSources = {"stderr":               self.stdErrText(),
                        "QProcessErrorText":    self.__QProcessErrorText,
                        "QIODeviceErrorText":   self.errorString() if not self.__QIODeviceDefaultErrorString else "" }   # Drop QIODevice's spurious default message of ~'Unknown error'.
        # Note that error texts are stripped, so they have to be substantive...
        response = delimiter.join(": ".join([key, value.strip()]) for (key, value) in sorted(errorSources.items()) if value)
        return response


    def succeeded(self):
        return self.__finished and self.__succeeded and (not self.stdErrText())      # stdErr checked because of edge case where QProcess claims to finish and succeed (but writes its own failure to stderr!) -- e.g. "QProcessPrivate::execChild() failed to chdir"...

    def failed(self):
        return self.__finished and not self.succeeded()


    def isValid(self):
        try: # An arbitrary interrogation to see if underlying c++ wrapper object has been deleted
            self.objectName()
            return True
        except RuntimeError:
            return False

    def isRunning(self):
        return self.state() == self.Running

    def isStarting(self):
        return self.state() == self.Starting