Python PyQt5如何读取/写入QProcess

Python PyQt5如何读取/写入QProcess,python,pyqt,pyqt5,Python,Pyqt,Pyqt5,我有一个PyQt5 GUI应用程序,希望执行一个外部程序,并在QTextEdit小部件上显示外部程序的stdout、stderr和stdin。我已经为stdout和stderr做到了这一点。我需要外部进程的stdin帮助 想象一下下面的片段 self.te = QTextEdit(self) self.te.move(self.x0, 150) self.te.resize(self.mainWinWidth - 100, self.mainWinHei

我有一个PyQt5 GUI应用程序,希望执行一个外部程序,并在QTextEdit小部件上显示外部程序的stdout、stderr和stdin。我已经为stdout和stderr做到了这一点。我需要外部进程的stdin帮助

想象一下下面的片段

       self.te = QTextEdit(self)
       self.te.move(self.x0, 150)
       self.te.resize(self.mainWinWidth - 100, self.mainWinHeight - 200)
以及启动QProcess的代码片段

      self.process = QtCore.QProcess(self)
      self.process.setProcessChannelMode( QProcess.MergedChannels )
      self.process.readyRead.connect(self.readReady)
      # ... and elsewhere I start the sub process like
      os.environ["PYTHONUNBUFFERED"] = "1"
      self.process.start('./goo', [])
和readreadready()实现为:

    def readReady(self):
        cursor = self.te.textCursor()
        cursor.movePosition(cursor.End)
        cursor.insertText(str(self.process.readAll(), 'utf-8'))
        self.te.ensureCursorVisible()
而goo(1)是一个基本的子流程,按照

#!/usr/bin/python3

import time
import sys

for i in range(0,5):
    print(f"============ {i} ===")
    time.sleep(1)

sys.stderr.write("Testing stderr...\n")
print("Enter name:")
name = sys.stdin.readline()
print(f"Got {name}")
话虽如此,我确实看到stdout和stderr都正常工作。我还看到了“entername:”,但当我在qtexedit上输入“joe”或“moe”时,什么也没有发生,即后端子进程仍在等待

看来我需要一个事件处理程序来写。也就是说,当子进程(通过QProcess)等待其stdin上的输入时,我需要检测到它,并以某种方式从QTextEdit(从用户)读取它,然后将它馈送到子进程(即写入它的stdin)

想想ssh、telnet或xterm。没有现成的小部件吗

您必须使用QProcess的方法:

├── goo
└── main.py
导入操作系统
导入系统
从PyQt5导入QtCore、QtGui、QtWidgets
类小部件(qtwidts.QWidget):
def uuu init uuu(self,parent=None):
super()。\uuuu init\uuuu(父级)
self._textedit=QtWidgets.QTextEdit(只读=True)
self._lineedit=QtWidgets.QLineEdit()
self.\u button=qtwidts.QPushButton(“发送”)
self.\u按钮。点击。连接(self.on.\u点击)
lay=qtwidts.QGridLayout(self)
lay.addWidget(self.\u textedit,0,0,1,2)
lay.addWidget(self.\u lineedit,1,0)
lay.addWidget(self.\u按钮,1,1)
self.\u进程=QtCore.QProcess(self)
self.\u process.setProcessChannelMode(QtCore.QProcess.MergedChannels)
self.\u process.readyRead.connect(self.on\u readreadready)
current_dir=os.path.dirname(os.path.realpath(uu文件_uu))
self.\u process.start(os.path.join(当前目录,“goo”))
@QtCore.pyqtSlot()
def on_ReadReadReady(自):
cursor=self.\u textedit.textCursor()
cursor.movePosition(QtGui.QTextCursor.End)
cursor.insertText(str(self.\u process.readAll(),“utf-8”))
self.\u textedit.ensurercursorvisible()
@QtCore.pyqtSlot()
已单击的def(自身):
text=self.\u lineedit.text()+“\n”
self.\u process.write(text.encode())
如果名称=“\uuuuu main\uuuuuuuu”:
os.environ[“PYTHONUNBUFFERED”]=“1”
app=qtwidts.QApplication(sys.argv)
w=Widget()
w、 show()
sys.exit(app.exec_())
您必须使用QProcess的方法:

├── goo
└── main.py
导入操作系统
导入系统
从PyQt5导入QtCore、QtGui、QtWidgets
类小部件(qtwidts.QWidget):
def uuu init uuu(self,parent=None):
super()。\uuuu init\uuuu(父级)
self._textedit=QtWidgets.QTextEdit(只读=True)
self._lineedit=QtWidgets.QLineEdit()
self.\u button=qtwidts.QPushButton(“发送”)
self.\u按钮。点击。连接(self.on.\u点击)
lay=qtwidts.QGridLayout(self)
lay.addWidget(self.\u textedit,0,0,1,2)
lay.addWidget(self.\u lineedit,1,0)
lay.addWidget(self.\u按钮,1,1)
self.\u进程=QtCore.QProcess(self)
self.\u process.setProcessChannelMode(QtCore.QProcess.MergedChannels)
self.\u process.readyRead.connect(self.on\u readreadready)
current_dir=os.path.dirname(os.path.realpath(uu文件_uu))
self.\u process.start(os.path.join(当前目录,“goo”))
@QtCore.pyqtSlot()
def on_ReadReadReady(自):
cursor=self.\u textedit.textCursor()
cursor.movePosition(QtGui.QTextCursor.End)
cursor.insertText(str(self.\u process.readAll(),“utf-8”))
self.\u textedit.ensurercursorvisible()
@QtCore.pyqtSlot()
已单击的def(自身):
text=self.\u lineedit.text()+“\n”
self.\u process.write(text.encode())
如果名称=“\uuuuu main\uuuuuuuu”:
os.environ[“PYTHONUNBUFFERED”]=“1”
app=qtwidts.QApplication(sys.argv)
w=Widget()
w、 show()
sys.exit(app.exec_())

不错。。。因此,您使用“on_click on send”从QTextLine获取输入并将其馈送到QProcess。。。。如果子进程是一个很长的交互式程序,有数百行输出和许多交互,该怎么办。我有一个不耐烦的用户,他会在文本行中输入冒昧的答案。这不会混淆事件循环并将不正确的数据传递给处理程序吗?是否可以禁用(或灰显)文本行,直到子进程准备好输入(可能通过writerady之类的方式),然后启用文本行并再次禁用它。@user3912225是的,这是可能的。您必须根据需要使用
self.\u lineedit.setEnabled(True)
self.\u lineedit.setEnabled(False)
。(其他小部件也可以这样做,比如禁用按钮),但这取决于您的逻辑。我的解决方案仅基于您提供的MRE。我一定会将此标记为已接受/正确。最后一部分,因为你一直都很好。是否存在类似QProcess.writerady()的事件@user3912225不,没有。写入是同步进行的,因此不需要信号。您可以使用
WaitForBytesWrited(-1)
来确保它是编写的,但我认为这不是必需的。很好。。。因此,您使用“on_click on send”从QTextLine获取输入并将其馈送到QProcess。。。。如果子进程是一个很长的交互式程序,有数百行输出和许多交互,该怎么办。我有一个不耐烦的用户,他会在文本行中输入冒昧的答案。这不会混淆事件循环并将不正确的数据传递给处理程序吗?是否可以禁用(或灰显)文本行,直到子进程准备好输入(可能通过writerady之类的方式),然后启用文本行并再次禁用它。@user3912225是的,这是可能的。您必须使用
self.\u lineedit.setEnabled(True)
self.\u line