我有这个非常基本的应用程序,打算在一个textEdit
组件上评估给定的Python代码,并在另一个组件上显示结果。
import sys
from PyQt4 import QtGui
from cStringIO import StringIO
class SampleGUI(QtGui.QWidget):
def __init__(self):
super(SampleGUI, self).__init__()
self.initGUI()
def initGUI(self):
self.code = QtGui.QTextEdit()
self.result = QtGui.QTextEdit()
btn = QtGui.QPushButton('Evaluate')
btn.clicked.connect(self.evaluate)
vbox = QtGui.QVBoxLayout()
vbox.addWidget(self.code)
vbox.addWidget(btn)
vbox.addWidget(self.result)
self.setLayout(vbox)
self.show()
def evaluate(self):
source_code = str(self.code.toPlainText())
old_stdout = sys.stdout
redirected_output = sys.stdout = StringIO()
exec source_code
sys.stdout = old_stdout
self.result.setText(redirected_output.getvalue())
def main():
app = QtGui.QApplication([])
s = SampleGUI()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
到目前为止,这项工作效果很好,您不会要求输入值。假设您在控制台中使用python samplegui.py
运行脚本,如果您碰巧在第一个文本框中输入了类似的内容:
a = 3
print 5 + a
b = input()
print 1 + b
然后按Evaluate
,应用程序需要从控制台输入值 。输入一些值并按回车键后,它会继续并正确评估。
我想要实现的是将stdin
重定向到我可以在GUI
内部操作的组件。
我该怎么做?理想情况下,我想在Python解释器样式中执行此操作,其中输出和输入以交互方式发生。另一种选择可能是在应用程序等待输入并显示输入对话框时以某种方式处理/捕获信号。
修改
事实证明它比我想象的要容易。在这里,您可以看到使用sys.stdin
拦截QInputDialog
的脚本版本,以便用户可以从GUI
输入值。
import sys
from PyQt4 import QtGui
from cStringIO import StringIO
class InputGUI():
def __init__(self, parentWidget):
self.parentWidget = parentWidget
def readline(self):
text, ok = QtGui.QInputDialog.getText(self.parentWidget, 'Introduce value', 'Value:')
if ok:
return str(text)
else:
return ''
class SampleGUI(QtGui.QWidget):
def __init__(self):
super(SampleGUI, self).__init__()
self.initGUI()
def initGUI(self):
self.code = QtGui.QTextEdit()
self.result = QtGui.QTextEdit()
btn = QtGui.QPushButton('Evaluate')
btn.clicked.connect(self.evaluate)
vbox = QtGui.QVBoxLayout()
vbox.addWidget(self.code)
vbox.addWidget(btn)
vbox.addWidget(self.result)
self.setLayout(vbox)
self.show()
def evaluate(self):
source_code = str(self.code.toPlainText())
streams = sys.stdin, sys.stdout
sys.stdin = InputGUI(self)
redirected_output = sys.stdout = StringIO()
exec source_code
sys.stdin, sys.stdout = streams
self.result.setText(redirected_output.getvalue())
def main():
app = QtGui.QApplication([])
s = SampleGUI()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
答案 0 :(得分:2)
我将sys.stdin
替换为实现文件描述符协议的自定义类的实例。然后,您可以简单地决定当用户想要通过input()
或sys.stdin.readline()
阅读内容时会发生什么。
至于实现文件描述符:实现documentation中涵盖的所有方法。此外,您可能希望实施context manager protocol,因此您的自定义sys.stdin
可以与with
语句一起使用。
但是,请注意,如果用户再次替换sys.stdin
,他们仍然可以用脚射击,但至少这似乎比调用input()
的人更不可能。