Spyder的界面控件库的路径可以通过如下的命令获得:
>>> widgets
widgets目录下的每个文件都是提供了一个Spyder界面控件,本文将介绍下面三个控件:
widgets\arrayeditor.py 数组编辑器
widgets\internalshell.py Python命令行
Spyder的代码编辑器提供了Python、Cython、Fortran、css、html、C/C++等语言的代码高亮显示。如果我们想在自己的项目中使用简单的代码编辑功能,直接使用Spyder的代码编辑器是十分便捷的。
下面是使用代码编辑器的例子:
import sys
from spyderlib.widgets.sourcecode.codeeditor import CodeEditor
app = QApplication(sys.argv)
editor = CodeEditor()
editor.setup_editor( ❶
language = "python",
font = QFont("Courier New")
)
editor.set_text(file(__file__).read()) ❷
editor.show()
sys.exit(app.exec_())
在创建CodeEditor对象之后,❶调用setup_editor()设置编辑器的各种属性。下面是setup_editor()的参数列表及其缺省值:
font=None, color_scheme=None, wrap=False, tab_mode=True,
intelligent_backspace=True, highlight_current_line=True,
occurence_highlighting=True, scrollflagarea=True,
edge_line=True, edge_line_column=79,
codecompletion_auto=False, codecompletion_case=True,
codecompletion_single=False, codecompletion_enter=False,
calltips=None, go_to_definition=False,
close_parentheses=True, auto_unindent=True,
indent_chars=" "*4, tab_stop_width=40, cloned_from=None):
...
在本例中通过设置language和font参数,将语法高亮改为Python,并将字体改为等宽的”Courier New”字体。
❷调用set_text()设置编辑器的文本内容。CodeEditor的各种方法可以通过查看CodeEditor及其父类TextEditBaseWidget的代码获得。而由于TextEditBaseWidget从QPlainTextEdit继承,因此还可以查看Qt的手册以了解更多的方法,例如toPlainText()可以获得编辑器中的文本。另外还可以通过Spyder的Preference对话框查看编辑器所支持的各种快捷键。
使用Qt实现一个编辑二维数据的表格控件是一件十分繁琐的工作。幸好Spyder提供了多种用于编辑对象的编辑器,可以直接用来编辑列表、字典以及数组。下面是编辑数组的演示程序:
import sys
import numpy as np
from spyderlib.widgets.arrayeditor import ArrayEditorWidget
app = QApplication(sys.argv)
data = np.random.randn(6, 4)
editor = ArrayEditorWidget(None, data) ❶
editor.show()
app.exec_()
editor.accept_changes() ❷
print data
❶ArrayEditorWidget的第一个参数为拥有此控件的父控件,由于这里直接将数组编辑器显示为窗口,因此其父控件为None。第二个参数为所编辑的数组。❷在窗口关闭之后,调用编辑器的accept_changes()将编辑器中修改的内容写回数组。
下面是使用字典编辑器的例子:
from PyQt4.QtGui import QApplication
from spyderlib.widgets.dicteditor import DictEditorWidget
app = QApplication(sys.argv)
editor =DictEditorWidget(None, globals()) ❶
editor.show()
sys.exit(app.exec_())
❶创建DictEditorWidget对象时,将全局变量字典传递给它,因此字典编辑器将显示所有的全局变量。
在界面中添加Python命令行可以方便我们对程序进行调试,观察程序中各个对象的属性,以及运行它们的各种方法。
from spyderlib.widgets.internalshell import InternalShell
class Demo(QWidget):
def __init__(self):
super(Demo, self).__init__()
self.shell = InternalShell(self, {"demo":self}, ❶
multithreaded = False,
max_line_count = 3000,
font = QFont("Courier new", 10)
)
self.line_edit = QLineEdit() ❷
vbox = QVBoxLayout()
vbox.addWidget(self.line_edit)
vbox.addWidget(self.shell)
self.setLayout(vbox)
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
demo = Demo()
demo.show()
sys.exit(app.exec_())
❶创建一个InternalShell对象,它的第二个参数为此对象的名字空间。在本例的命令行控件中可以通过demo变量访问表示窗口的对象。❷为了演示命令行的功能,我们添加了一个行文本编辑控件。程序的运行界面如下图所示:
图中通过在命令行中运行:
将文本编辑框中的文字改为”hello world”。
下面我们结合上述的三种控件,制作一个简单的Python运行工具。在这个程序中,用户通过编辑器编辑Python程序,然后按F5运行在命令行的名字空间中运行程序。名字空间中的数据对象将显示在字典编辑器中。下面是完整的程序:
from PyQt4.QtGui import (QApplication, QWidget, QFont, QListWidget,
QHBoxLayout, QVBoxLayout, QShortcut, QKeySequence)
import numpy as np
from spyderlib.widgets.sourcecode.codeeditor import CodeEditor
from spyderlib.widgets.internalshell import InternalShell
from spyderlib.widgets.dicteditor import DictEditorWidget
class Demo(QWidget):
def __init__(self):
super(Demo, self).__init__()
self.code_editor = CodeEditor(self)
self.code_editor.setup_editor(
language = "python",
font = QFont("Courier New")
)
run_sc = QShortcut(QKeySequence("F5"), self, self.run) ❶
self.shell = InternalShell(self, {"demo":self},
multithreaded = False,
max_line_count = 3000,
font = QFont("Courier new", 10)
)
self.dict_editor = DictEditorWidget(self, {})
self.dict_editor.editor.set_filter(self.filter_namespace) ❷
self.dict_editor.set_data(self.shell.interpreter.namespace) ❸
vbox = QVBoxLayout()
vbox.addWidget(self.code_editor)
vbox.addWidget(self.shell)
hbox = QHBoxLayout()
hbox.addWidget(self.dict_editor)
hbox.addLayout(vbox)
self.setLayout(hbox)
self.resize(800, 600)
def filter_namespace(self, data):
result = {}
support_types = [np.ndarray, int, long, float, str, tuple, dict, list]
for key, value in data.iteritems():
if not key.startswith("__") and type(value) in support_types:
result[key] = value
return result
def run(self):
code = str(self.code_editor.toPlainText())
namespace = self.shell.interpreter.namespace
exec code in namespace ❹
self.dict_editor.set_data(namespace) ❺
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
try:
demo = Demo()
demo.show()
except Exception as ex:
import traceback
sys.__stdout__.write(traceback.format_exc()) ❻
sys.exit(app.exec_())
❶创建一个F5快捷键,当F5按下时将运行run()。
❷在命令行的名字空间中除了数据对象之外,还有许多非数据对象,因此这里通过filter_namespace()对名字空间进行过滤,只显示变量名不以”__”开头、如下的类型对象:
❸调用字典编辑器的set_data()设置其所编辑的字典,这里将命令行控件的名字空间通过传递给它。
❹在run()中,首先在命令行的名字空间中运行代码编辑器中的程序,❺然后调用字典编辑器的set_data()刷新字典编辑器的显示。
❻由于系统的标准输入输出都改为了命令行,为了显示错误信息,我们捕捉所有的异常,并通过sys.__stdout__将异常信息输出到控制台窗口中。
程序的运行界面如下: