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

2024-10-03 11:16:07 发布

您现在位置:Python中文网/ 问答频道 /正文

我想做什么?

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

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

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

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

我的问题

我的问题是我的代码无法到达第二个返回。 换言之,模拟继续进行。 不管怎样,子进程永远不会收到第二个返回。在

复制步骤

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

注意事项:

  • 我已经在FedoraLinux上编写了代码。 如果你在运行Ubuntu,你可能需要将可执行文件的路径改为/usr/bin/s51(我不确定确切的路径)。

  • 这些代码在其他一些控制台应用程序上“运行良好”,比如bash、python、ifconfig、echo、gcc。。。

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

  • 编辑1:我正在运行qt4.8.3

  • 编辑2:简化并修复了代码+添加了一个屏幕截图

屏幕截图

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

(我输入了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_()

Tags: 代码selfmaindefconnectprocessqtguiqtcore