输入特定命令后,QProcess停止通信

时间:2014-12-27 02:54:56

标签: python linux qt qprocess sdcc

我想做什么?

我正在尝试构建一个允许我轻松运行/调试的Python Qt Gui 嵌入式微控制器程序。 作为编译器,我使用sdcc。 Sdcc还包含一个模拟器。

在代码中,我启动了一个运行微控制器模拟器(s51)的子QProcess。

在模拟器中,模拟首先输入r + RETURN("r\n")。

按RETURN("\n")可以随时停止模拟。

我的问题

我的问题是我的代码无法进入第二个RETURN。 换句话说,模拟继续无限。 无论如何,子进程永远不会收到第二个RETURN。

重现的步骤

  1. 安装Python,PyQt和sdcc。
  2. 将以下代码复制/存放在emtpy文件中并运行它。
  3. 最终更改s51可执行文件的路径。
  4. 点击"开始"按钮。
  5. 在下面的输入中输入r,然后按Return键。 现在应该开始模拟了。
  6. 第二次按Return键时,模拟应停止。但事实并非如此。
  7. 备注:

    • 我已经在Fedora Linux上编写了代码。 如果您正在运行Ubuntu,则可能必须将可执行文件的路径更改为/usr/bin/s51(我不确定具体路径)。

    • 代码'工作正常'在其他一些控制台应用程序上,如bash,python,ifconfig,echo,gcc,...

    • 我认为这个问题与sdcc在阅读" r \ n"之后立即执行ioct有关。命令(使用strace找到): ioctl(0, SNDCTL_TMR_TIMEBASE or SNDRV_TIMER_IOCTL_NEXT_DEVICE or TCGETS, {B38400 opost isig icanon echo ...}) = 0

    • EDIT1:我正在运行Qt 4.8.3

    • EDIT2:简化&修复了代码+添加了截图

    截图

    模拟应该在第二次返回后停止。

    (我输入了h run\nrun\n\n\n\helpScreen shot can be found here (not enough reputation)

    SimpleConsole.py

    #!/usr/bin/env python3
    
    import sys
    from PyQt4 import Qt, QtGui, QtCore
    
    class SimpleConsole(QtGui.QMainWindow):
      def __init__(self):
        QtGui.QMainWindow.__init__(self)
        self.setup()
        self.process = None
    
      def setup(self):
        l = QtGui.QHBoxLayout()
        lbl = QtGui.QLabel('Command:')
        self.processExecutable = QtGui.QLineEdit()
        self.processExecutable.setEnabled(True)
        self.processExecutable.returnPressed.connect(self.startStopProcess)
        self.processExecutable.setText('/usr/libexec/sdcc/s51')
        lbl.setBuddy(self.processExecutable)
        l.addWidget(lbl)
        l.addWidget(self.processExecutable)
    
        self.processOutputWidget = QtGui.QTextEdit()
        self.processOutputWidget.setReadOnly(True)
        self.processInputWidget = QtGui.QLineEdit()
        self.processInputWidget.setEnabled(False)
        self.processInputWidget.returnPressed.connect(self.inputForProcess)
        main = QtGui.QVBoxLayout()
        main.addLayout(l)
        main.addWidget(self.processOutputWidget)
        main.addWidget(self.processInputWidget)
    
        widget = QtGui.QWidget()
        widget.setLayout(main)
        self.setCentralWidget(widget)
        self.setStatusBar(QtGui.QStatusBar())
        self.statusBarLabel = QtGui.QLabel()
        self.statusBar().addWidget(self.statusBarLabel)
        self.toolbar = QtGui.QToolBar()
        self.addToolBar(self.toolbar)
        self.startStopAction = self.toolbar.addAction('Start')
        self.startStopAction.triggered[bool].connect(self.startStopProcess)
    
      def closeEvent(self, event):
        self.stopProcess()
    
      @QtCore.pyqtSlot(QtCore.QProcess.ProcessState)
      def processStateChanged(self, newState):
        self.processInputWidget.setEnabled(newState == QtCore.QProcess.Running)
        pid = self.process.pid()
        if newState == QtCore.QProcess.Running:
          self.startStopAction.setText('Stop')
          self.startStopAction.setEnabled(True)
          self.processExecutable.setEnabled(False)
        elif newState == QtCore.QProcess.NotRunning:
          self.processInputWidget.setEnabled(False)
          self.processInputWidget.clear()
          self.startStopAction.setText('Start')
          self.startStopAction.setEnabled(True)
          self.processExecutable.setEnabled(True)
          self.process = None
        status = {QtCore.QProcess.NotRunning:'not running',
          QtCore.QProcess.Starting:'starting',
          QtCore.QProcess.Running:'running'}
        self.statusBarLabel.setText('Process state change: {newState}. (pid={pid})'.format(newState=status[newState], pid=pid))
    
      @QtCore.pyqtSlot()
      def startStopProcess(self):
        if self.process:
          self.stopProcess()
        else:
          self.processOutputWidget.clear()
          self.process = QtCore.QProcess(self)
          self.process.stateChanged.connect(self.processStateChanged)
          self.process.readyReadStandardOutput.connect(self.processOutputRead)
          self.process.readyReadStandardError.connect(self.processErrorRead)
    
          exe = self.processExecutable.text()
          self.process.start(exe, QtCore.QIODevice.ReadWrite)
    
      def moveCursorToEnd(self):
        self.processOutputWidget.moveCursor(QtGui.QTextCursor.End, QtGui.QTextCursor.MoveAnchor)
    
      @QtCore.pyqtSlot()
      def inputForProcess(self):
        cmd = self.processInputWidget.text() + '\n'
        self.moveCursorToEnd()
        self.processOutputWidget.insertPlainText(cmd)
        self.process.writeData(bytearray(cmd, encoding='utf-8'))
        self.process.waitForBytesWritten()
        self.processInputWidget.clear()
    
      @QtCore.pyqtSlot()
      def processOutputRead(self):
        bytesOut = bytes(self.process.readAllStandardOutput()).decode('utf-8')
        self.moveCursorToEnd()
        self.processOutputWidget.insertPlainText(bytesOut)
    
      @QtCore.pyqtSlot()
      def processErrorRead(self):
        bytesError = bytes(self.process.readAllStandardError()).decode('utf-8')
        self.moveCursorToEnd()
        self.processOutputWidget.insertPlainText(bytesError)
    
      def stopProcess(self):
        if self.process:
          self.process.closeWriteChannel()
          if not self.process.waitForFinished(500):
            self.process.terminate()
    
    if __name__ == '__main__':
      app = QtGui.QApplication(sys.argv)
      w = SimpleConsole()
      w.show()
      app.exec_()
    

0 个答案:

没有答案