How to embed a Python interpreter in a PyQT widget(如何在 PyQT 小部件中嵌入 Python 解释器)
问题描述
我希望能够从我的 python 应用程序中调出一个交互式 python 终端.我的程序中的一些(但不是全部)变量需要暴露给解释器.
I want to be able to bring up an interactive python terminal from my python application. Some, but not all, variables in my program needs to be exposed to the interpreter.
目前我使用子分类和修改的 QPlainTextEdit
并将所有命令"路由到 eval
或 exec
,并跟踪字典中的单独命名空间.然而,必须有一种更优雅、更健壮的方式!怎么样?
Currently I use a sub-classed and modified QPlainTextEdit
and route all "commands" there to eval
or exec
, and keep track of a separate namespace in a dict. However there got to be a more elegant and robust way! How?
这是一个我想要的例子,但它是用 IPython 和 pyGTK ...http://ipython.scipy.org/moin/Cookbook/EmbeddingInGTK
Here is an example doing just what I want, but it is with IPython and pyGTK... http://ipython.scipy.org/moin/Cookbook/EmbeddingInGTK
以下是我目前拥有的.但是有很多角落案例,我可能错过了一些.它很慢,尝试一个大的打印循环......它必须是一种更简单且不易出错的方式,......我希望!!
Below is what I currently have. But there are so many corner cases that I probably missed some. It is very slow, try a large print loop... It got to be a simpler and less bug prone way, ...I hope!!
def runCommand(self)
函数是理解我的问题的关键.理想情况下,我不想改进它,我宁愿用更简单、更智能的东西替换它的内容.
It is the def runCommand(self)
function that is the key to understanding my problem. I ideally don't want to improve it, I rather want to replace its content with something simpler and smarter.
main"中 console.updateNamespace({'myVar1' : app, 'myVar2' : 1234})
语句的功能也很重要.
The functionality of the console.updateNamespace({'myVar1' : app, 'myVar2' : 1234})
statement in "main" is also important.
import sys, os
import traceback
from PyQt4 import QtCore
from PyQt4 import QtGui
class Console(QtGui.QPlainTextEdit):
def __init__(self, prompt='$> ', startup_message='', parent=None):
QtGui.QPlainTextEdit.__init__(self, parent)
self.prompt = prompt
self.history = []
self.namespace = {}
self.construct = []
self.setGeometry(50, 75, 600, 400)
self.setWordWrapMode(QtGui.QTextOption.WrapAnywhere)
self.setUndoRedoEnabled(False)
self.document().setDefaultFont(QtGui.QFont("monospace", 10, QtGui.QFont.Normal))
self.showMessage(startup_message)
def updateNamespace(self, namespace):
self.namespace.update(namespace)
def showMessage(self, message):
self.appendPlainText(message)
self.newPrompt()
def newPrompt(self):
if self.construct:
prompt = '.' * len(self.prompt)
else:
prompt = self.prompt
self.appendPlainText(prompt)
self.moveCursor(QtGui.QTextCursor.End)
def getCommand(self):
doc = self.document()
curr_line = unicode(doc.findBlockByLineNumber(doc.lineCount() - 1).text())
curr_line = curr_line.rstrip()
curr_line = curr_line[len(self.prompt):]
return curr_line
def setCommand(self, command):
if self.getCommand() == command:
return
self.moveCursor(QtGui.QTextCursor.End)
self.moveCursor(QtGui.QTextCursor.StartOfLine, QtGui.QTextCursor.KeepAnchor)
for i in range(len(self.prompt)):
self.moveCursor(QtGui.QTextCursor.Right, QtGui.QTextCursor.KeepAnchor)
self.textCursor().removeSelectedText()
self.textCursor().insertText(command)
self.moveCursor(QtGui.QTextCursor.End)
def getConstruct(self, command):
if self.construct:
prev_command = self.construct[-1]
self.construct.append(command)
if not prev_command and not command:
ret_val = '
'.join(self.construct)
self.construct = []
return ret_val
else:
return ''
else:
if command and command[-1] == (':'):
self.construct.append(command)
return ''
else:
return command
def getHistory(self):
return self.history
def setHisory(self, history):
self.history = history
def addToHistory(self, command):
if command and (not self.history or self.history[-1] != command):
self.history.append(command)
self.history_index = len(self.history)
def getPrevHistoryEntry(self):
if self.history:
self.history_index = max(0, self.history_index - 1)
return self.history[self.history_index]
return ''
def getNextHistoryEntry(self):
if self.history:
hist_len = len(self.history)
self.history_index = min(hist_len, self.history_index + 1)
if self.history_index < hist_len:
return self.history[self.history_index]
return ''
def getCursorPosition(self):
return self.textCursor().columnNumber() - len(self.prompt)
def setCursorPosition(self, position):
self.moveCursor(QtGui.QTextCursor.StartOfLine)
for i in range(len(self.prompt) + position):
self.moveCursor(QtGui.QTextCursor.Right)
def runCommand(self):
command = self.getCommand()
self.addToHistory(command)
command = self.getConstruct(command)
if command:
tmp_stdout = sys.stdout
class stdoutProxy():
def __init__(self, write_func):
self.write_func = write_func
self.skip = False
def write(self, text):
if not self.skip:
stripped_text = text.rstrip('
')
self.write_func(stripped_text)
QtCore.QCoreApplication.processEvents()
self.skip = not self.skip
sys.stdout = stdoutProxy(self.appendPlainText)
try:
try:
result = eval(command, self.namespace, self.namespace)
if result != None:
self.appendPlainText(repr(result))
except SyntaxError:
exec command in self.namespace
except SystemExit:
self.close()
except:
traceback_lines = traceback.format_exc().split('
')
# Remove traceback mentioning this file, and a linebreak
for i in (3,2,1,-1):
traceback_lines.pop(i)
self.appendPlainText('
'.join(traceback_lines))
sys.stdout = tmp_stdout
self.newPrompt()
def keyPressEvent(self, event):
if event.key() in (QtCore.Qt.Key_Enter, QtCore.Qt.Key_Return):
self.runCommand()
return
if event.key() == QtCore.Qt.Key_Home:
self.setCursorPosition(0)
return
if event.key() == QtCore.Qt.Key_PageUp:
return
elif event.key() in (QtCore.Qt.Key_Left, QtCore.Qt.Key_Backspace):
if self.getCursorPosition() == 0:
return
elif event.key() == QtCore.Qt.Key_Up:
self.setCommand(self.getPrevHistoryEntry())
return
elif event.key() == QtCore.Qt.Key_Down:
self.setCommand(self.getNextHistoryEntry())
return
elif event.key() == QtCore.Qt.Key_D and event.modifiers() == QtCore.Qt.ControlModifier:
self.close()
super(Console, self).keyPressEvent(event)
welcome_message = '''
---------------------------------------------------------------
Welcome to a primitive Python interpreter.
---------------------------------------------------------------
'''
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
console = Console(startup_message=welcome_message)
console.updateNamespace({'myVar1' : app, 'myVar2' : 1234})
console.show();
sys.exit(app.exec_())
推荐答案
我知道的有点晚,但我推荐 code.InteractiveConsole 类:http://docs.python.org/py3k/library/code.html#code.InteractiveConsole
Bit late I know, but I recommend the code.InteractiveConsole class: http://docs.python.org/py3k/library/code.html#code.InteractiveConsole
这篇关于如何在 PyQT 小部件中嵌入 Python 解释器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:如何在 PyQT 小部件中嵌入 Python 解释器
- 使用公司代理使Python3.x Slack(松弛客户端) 2022-01-01
- ";find_element_by_name(';name';)";和&QOOT;FIND_ELEMENT(BY NAME,';NAME';)";之间有什么区别? 2022-01-01
- 检查具有纬度和经度的地理点是否在 shapefile 中 2022-01-01
- 我如何卸载 PyTorch? 2022-01-01
- 使用 Cython 将 Python 链接到共享库 2022-01-01
- YouTube API v3 返回截断的观看记录 2022-01-01
- CTR 中的 AES 如何用于 Python 和 PyCrypto? 2022-01-01
- 如何使用PYSPARK从Spark获得批次行 2022-01-01
- 计算测试数量的Python单元测试 2022-01-01
- 我如何透明地重定向一个Python导入? 2022-01-01