第四章 用PyCrust使得wxPython更易处理
PyCrust
是一个图形化的shell
程序,使用wxPython
写成,它可以用来帮助你分析你的wxPython
程序。
为何称它为PyCrust
?这是因为当Patrick O’Brien
使用wxPython
创建一个交互式的Python
shell
时,PyShell
已被使用了,所以选用了PyCrust
这个名字。
PyCrust
是Py
包中的一部分,Py
包目前被包含在wxPython
中。这个Py
包还包含了其它相关功能的程序,这包括PyFilling
, PyAlaMode
, PyAlaCarte
, 和PyShell
。这些程序每个都是想成为融图形化、点击环境 、wxPython
的交互、内省运行特点为一体。但是PyCrust
表现最完善。
在这章中,我们将说明PyCrust
和那些相关程序都干些什么,还有,你如何使用它们才能使得你用wxPython
工作得更流畅。我们以谈论普通的Python
shell
作为开始,然后专门针对PyCrust
,最后我们将涉及Py
包中剩下的程序。
如何与wxPython程序交互?
与其它编程语言相比,Python
的一个显著的特点是你可以以两种方式来使用它:你可以用它来运行存在的使用Python
语言写的程序,或从命令提示符来交互地运行Python
。交互地运行Python
如同与Python
解释器会话。
在下例4.1中,我们从命令行启动Python
,并键入一些数学运算。Python
启动后显示几行信息,然后是它的主提示符' '。当你键入的东西要求额外的代码行时,Python
显示它的次提示符'...'。
例4.1 简单的Python
交互式会话
$ Python
Python 2.3.3 (#1, Jan 25 2004, 11:06:18)
[GCC 3.2.2 (Mandrake Linux 9.1 3.2.2-3mdk)] on linux2
Type "help", "copyright", "credits" o "license" for more information.
2 + 2
4
7 * 6
42
5 ** 3
125
for n in range(5):
... print n * 9
...
0
9
18
27
36
交互式的Python
不仅仅是一个好的桌面计算器,它也是一个好的学习工具,因为它提供了及时的反馈。当你有疑问时,你可以运行Python
,键入几行试验性的代码,看Python
如何反应,据此调整你的主要代码。学习Python
或学习现有的Python
代码是如何工作的,最好的方法之一就是交互式地调试。
PyCrust
配置了标准的Python
shell
当你交互式的使用Python
工作时,你工作在一个称为Python
shell
的环境中,它类似于其它的shell
环境,如微软平台的DOS
窗口,或类Unix
系统的bash
命令行。
所有Python
shell
中最基本的是例4.1中所出现的,它是你从命令行启动Python
时所见到的。虽然它是一个有用的shell
,但是它基于文本的,而非图形化的,并且它不提供快捷方式或有帮助的提示。有几个图形化的Python
shell
已经被开发出来了,它们提供了这些额外的功能。最著名的是IDLE
,它是Python
发布版的标准部分。IDLE
如下图4.1所示:
IDLE
看起来很像命令行Python
shell
,但是它有额外的特性如调用提示。
其它的Python
开发工具,如PythonWin
和Boa
Constructor
,包括了类似于IDLE
中的图形化Python
shell
。虽然每种工具的shell
各有一些有用的特性,如命令再调用(recall)
、自动完成、调用提示,但是没有一个工具完整包含了所有的特性 。在这种情况下,PyCrust
产生了,PyCrust
的目的之一就是提供所有现存的Python
shell
的特性。
创建PyCrust
的另一个动机是:使用一个GUI
工具包所写的代码不能工作在另一个不同的GUI
工具包上。例如,IDLE
是用Tkinter
写的,而不是wxPython
。由于这样,如果你试图在IDLE
的Python
shell
中引入和使用wxPython
模块,那么你将陷入wxPython
的事件循环与Tkinter
事件循环间的冲突,结果将导致程序的冻结或崩溃。
事实上,这两个工具包将在控制事件循环上产生冲突。因此,如果你使用wxPython
模块工作时想要内省运行特性,你的Python
shell
必须是用wxPython
写的。由于没有现存的Python
shell
支持完整的特性,PyCrust
被创建来填补这种需要。
PyCrust的有用特性是什么?
现在,我们将关注PyCrust
提供的shell
的一些特性。PyCrust
的shell
看起来有些熟悉,这是因为它也显示了如同命令行Python
shell
相同的信息行和提示符。下图4.2显示了一个打开着的PyCrust
的屏幕:
你应该注意一下这个PyCrust
框架,它包含了一个wx.SplitterWindow
控件,框架被分成两个区域:上部的区域看起来像通常的Python
shell
;底部的区域包含了一个Notebook
控件,这个控件包含了不同的标签,默认标签显示的信息是有关当前的名字空间的。上部区域是PyCrust
shell
,它有几个有用的特性,我们将在下面几节讨论。
自动完成
当你在一个对象名后键入一点号时将引发自动完成功能。PyCrust
将按字母顺序显示关于该对象的所有已知的属性的一个列表。当你在点号后输入字母时,在列表中的高亮选项将改变去匹配你所输入的字母。如果高亮选项正是你所要的,这时按下Tab
键,PyCrust
将为你补全该属性名的其余部分。
在下图4.3中,PyCrust
显示一个字符串对象的属性的列表。这个自动完成的列表包含了该对象的所有属性和方法。
图4.3
调用提示和参数默认
当你在一个可调用的对象名后键入左括号时,PyCrust
显示一个调用提示窗口(如图4.4),该窗口包含了所能提供的参数信息和文档字符串(如果可调用对象中定义了文档字符串的话)。
可调用对象可以是函数、方法、内建的或类。可调用对象的定义都可以有参数,并且可以有用来说明功能的文档字符串,以及返回值的类型。如果你知道如何使用该可调用对象,那么你可以忽略调用提示并继续键入。
图4.4
语法高亮
当你在shell
中键入代码时,PyCrust
根据它的重要性改变文本的颜色。例如,Python
的关键词用一种颜色显示,原义字符串用另一种颜色,注释用另一种颜色。这就使得你可以通过颜色来确认你的输入是否有误。
Python
帮助
PyCrust
完整地提供了关于Python
的帮助功能。Python
的帮助功能显示了几乎所有Python
方面的信息,如下图4.5所示
图4.5
Python
的帮助功能提供了另外一个提示符(help)
。在使用了help
之后,你可以通过在help
提示符之后键入quit
来退出帮助模式,返回到通常的Python
提示符( )。
命令重调用
在PyCrust
shell
中有多种方法可以用来减少重复输入。它们大都通过捕获你先前的键入来实现,如果有必要,你可以修改所捕获的内容,之后它们将之发送给Python
解释器。
例如,PyCrust
维护着当前会话中你所键入的所有命令的一个历史记录。你可以从命令历史记录中重调用你先前键入的任何Python
命令(一行或多行)。下表4.1显示了一个关于该功能的快捷键列表。
Ctrl
+上箭头:获取前一个历史项 Alt
+P:获取前一个历史项 Ctrl
+下箭头:获取下一个历史项 Alt
+N:获取下一个历史项 Shift
+上箭头:插入前一个历史项 Shift
+下箭头:插入下一个历史项 F8
:历史项命令补全(键入先前命令的少量字符并按F8
) Ctrl
+Enter
:在多行命令中插入新行
正如你所看到的,这儿有不同的命令用于获取和插入旧命令,它们通过PyCrust
如何处理当前wxPythob
提示符中所键入的文本被区分。要替换你的键入或插入一个旧的命令,可以使用快捷键来获取或插入一个历史项。
插入一行到一个多行命令中的工作与插入到一单行命令不同。要插入一行到一个多行命令,你不能只按Enter
键,因为这样将把当前的命令发送给Python
解释器。替代的方法是,按下Ctrl
+Enter
来插入一个中断到当前行。如果你处于行尾,那么一个空行被插入当前行之后。这个过程类似于你在一个通常的文本编辑中剪切和粘帖文本的方法。
最后一种重调用命令的方法是简单地将光标移到想要使用的命令,然后按Enter
键。PyCrust
复制该命令到当前的Python
提示符。然后你可以修改该命令或按Enter
键以将该命令提交给解释器。
快捷键让你可以快速地开发代码,并做每步的测试。例如,你可以定义一个新的Python
类,创建该类的一个实例,并看它的行为如何。然后,你可以返回到这个类的定义,增加更多的方法或编辑已有的方法,并创建一个新的实例。通过这样的反复,你可以将你的类的定义做得足够好,然后将它粘帖到你的源代码中。
剪切和粘贴
你可能想重用在shell
中已开发的代码,而避免重新键入。有时,你可能找到一些样例代码(可能来自在线的教程),你想把它用到一个Python
shell
中。PyCrust
提供了一些简单的剪切和粘贴选项,列表于下表4.2
Ctrl
+C:复制所选的文本,去掉提示符 Ctrl
+Shift
+C:复制所选的文本,保留提示符 Ctrl
+X:剪切所选的文本 Ctrl
+V:粘贴自剪贴板 Ctrl
+Shift
+V:粘贴自剪贴板的多个命令并运行
粘贴的另一个特性是:PyCrust
从所粘贴到PyCrust
shell
中的代码中识别并自动去掉标准的Python
提示符。这使得复制教程或email
信息中的例子代码,把它粘贴到PyCrust
中,并测试它变得简单了,省去了手工的清理。
某些时候,当你复制代码时,你可能想去除PyCrust
提示符,如当你复制代码到你的源文件中时。另一些时候,你可能想保留这个提示符,如录你复制例子到一个文档中,或把它发送到一个新闻组。当从shell
复制时,PyCrust
对这两种情况都提供了支持。
标准shell环境
在wxPython
环境中,PyCrust
的行为尽可能地与命令行的Python
shell
相同。不同的是,一旦Python
代码被输入到了PyCrust
shell
中,就没有办法来中断该代码的运行。例如,假定你在PyCrust
中写了一个无限循环,如下所示:
while
True:
... print
"Hello
" ...
在你按下Enter
之后,上面的代码被传送到Python
解释器,PyCrust
停止响应。要中断这个无限的循环,必须关闭PyCrust
程序。这个缺点是与命令行的Python
shell
对比而言的。命令行的Python
shell
保留了处理键盘中断(Ctrl
+C)的能力。在命令行的Python
shell
中你会看到如下的行为:
while True:
... print "Hello"
...
Hello
Hello
Hello
Hello
Hello
Hello
Hello
Hello
Hello
Hello
Hello
Traceback (most recent call last):
File " stdin ", line 2, in ?
KeyboardInterrupt
在GUI
环境中的事件处理的本质,使得设计出能够让PyCrust
中断一个无限循环或在shell
提示符中键入的长时间运行的代码序列的方法有很大的不同。将来的PyCrust
版本可能会提供对这个缺点的一个解决办法。幸运的是,在PyCrust
和标准命令shell
之间只有这一个不同点。在其它方面,PyCrust
shell
和命令行的Python
shell
工作的完全一样。
动态更新
当你在运行PyCrust
时,PyCrust
的shell
的所有特性都是动态地被更新的,这意味着,诸如“自动完成”和“调用提示”等特性是有效的,即使是在shell
提示符中定义的对象。例如图4.6和4.7所显示的会话,那么我们定义并使用了一个类。
在图4.6中,PyCrust
为新类显示了自动完成选项。 图4.6
在图4.7中,PyCrust
显示了关于类所定义的新的方法的调用提示。 图4.7
PyCrust
notebook
的标签是干什么的?
PyCrust
界面的下半部是一个notebook
控件,notebook
控件包括了几个带有有用信息的标签。PyCrust
开始时,你所看到的标签是“Namespace
”标签。
Namespace标签
如图4.8所示,Namespace
标签又被用wx.SplitterWindow
控件分成两部分。左边包含一个树控件,它显示当前的名字空间,而右边显示在名字空间树中当前被选择的对象的细节。
图4.8
名字空间树呈现一个关于在当前名字空间中所有对象的层次关系的视图。如果你运行Python
的内建函数locals()
,这些对象将作为返回结果。在图4.8中,我们已经导入了wx
包并在名字空间树中选择了它。右边显示了所选择的项目的名字,它的类型和它的当前值。如果对象有与之相关联的源代码,PyCrust
也将显示出来。这里,wx
是一个wxPython
包,所以PyCrust
显示__init__.py
文件的源代码,该文件位于wx
目录中。
右边显示的第一行是左边所选择的对象的全名,你可以把它复制并粘贴到PyCrust
shell
或你的应用程序源码中。例如,我们在PyCrust
中引入locale
模块并选择名字空间树中locale
/encoding_alias
/'en
'项,右边就显示了所选对象的完整名,你可以把它复制并粘贴到PyCrust
shell
中,如下所示:
import locale
locale.encoding_alias['en']
'ISO8859-1'
这里,PyCrust
给我们提供了一个全名( locale.encoding_alias
['en
']),它使用Python
的索引(['en
'])来引用encoding_alias
目录中的指定项目。这个机制同样适用于列表(list)
。如果你在名字空间树中发现了你想用在你的代码中的东西,那么PyCrust
给了你这精确语法去完成这个任务。
Display标签
Display
标签中用于显示一个对象。PyCrust
有一个内建函数pp()
,这个函数使用Python
的pprint
模块为显示一个对象。使用中不需要显式地引入和重复使用pprint
,在Display
中,这些信息随对象的更新而每次更新。
例如,如果我们在PyCrust
shell
中有一个列表,我们要在 Display
标签中显示它的内容,我们可以在PyCrust
shell
中使用pp()
,然后列表的内容就显示在 Display
标签中了。以后每当我们改变了列表的内容, Display
标签中的内容随即改变。
Calltip
标签显示了在Python
shell
中最近调用提示的内容。如果你的调用要求大量的参数,那么你可以选择Calltip
标签。当使用wxPython
包时,存在着大量的类,这些类有许多方法,这些方法又要求许多参数。例如,为了创建一人wx.Button
,你可能要提供八个参数,有一个是必须提供的,其它七个有默认的值。Calltip
标签显示了关于wx.Button
构造器的细节,如下所示:
__init__(self, Window parent, int id=-1, String label=EmptyString,
Point pos=DefaultPosition, Size size=DefaultSize,
long style=0, Validator validator=DefaultValidator,
String name=ButtonNameStr) - Button
Create and show a button. The preferred way to create standard buttons
is to use a standard ID and an empty label. In this case wxWigets will
automatically use a stock label that corresponds to the ID given. In
addition, the button will be decorated with stock icons under GTK+2.
由于wxPython
的类实际上是封装的C++的类,所以调用提示信息完全基于类的文档字符串。它们显示了底层C++类所需要的参数和类型信息。对于完全用Python
语言定义的对象,PyCrust
检查它们以确定它的参数特性。
Session标签
Session
标签是一个简单的文本控件,它列出了在当前shell
会话中所键入的所有命令。这使得剪切和粘贴命令以用在别处更为简单。
Dispatcher
标签
PyCrust
包括了一个名为dispatcher
的模块,它提供了在一个应用程序中联系对象的机制。PyCrust
使用dispatcher
来维持它的界面的更新,主要是在命令从shell
传送到Python
解释器时。图4.9中的Dispatcher
标签列出了关于信号经过分配机制后的路由。当使用PyCrust
工作时,这是它的主要用处。
图4.9
这里的Dispatcher
标签也演示了如何增加另一个标签到一个wx.Notebook
控件。下面这个在Dispatcher
标签上的文本控件的源码,演示了如何使用dispatcher
模块:
class DispatcherListing(wx.TextCtrl):
"""Text control containing all dispatches for session."""
def __init__(self, parent=None, id=-1):
style = (wx.TE_MULTILINE | wx.TE_READONLY |
wx.TE_RICH2 | wx.TE_DONTWRAP)
wx.TextCtrl.__init__(self, parent, id, style=style)
dispatcher.connect(receiver=self.spy)
def spy(self, signal, sender):
"""Receiver for Any signal from Any sender."""
text = '%r from %s' % (signal, sender)
self.SetInsertionPointEnd()
start, end = self.GetSelection()
if start != end:
self.SetSelection(0, 0)
self.AppendText(text + '\n')
现在我们已经看到了PyCrust
作为独立的Python
shell
和名子空间检查器能够做些什么,下面让我们关注在你的wxPython
程序中,PyCrust
的其它一些用法。
如何将PyCrust应用于wxPython应用程序
。
让我们假设你已经用wxPython
创建了一个程序,并且你的程序正在工作,现在你想更好地了解它是如何工作的。在这章的前面你已经看到了PyCrust
的特性,它们看起来对于理解你的程序的功能是非常有用的。
通过将你的程序的名字传递给PyWrap
,你能够用PyCrust
shell
来启动你的程序,不需要对你的程序作任何的改变。下例4.2显示了一个名为spare.py
的程序,我们准备对它使用PyCrust
。
例4.2
#!/usr/bin/env python
"""Spare.py is a starting point for simple wxPython programs."""
import wx
class Frame(wx.Frame):
pass
class App(wx.App):
def OnInit(self):
self.frame = Frame(parent=None, id=-1, title='Spare')
self.frame.Show()
self.SetTopWindow(self.frame)
return True
if __name__ == '__main__':
app = App()
app.MainLoop()
为了运行这个程序时使用PyCrust
,要将该程序的全路径传递给PyWrap
。在Linux
上,命令行类似如下:
$ pywrap spare.py
在windows
下,命令行类似如下:
F:\ python pywrap.py spare.py
在开始的时候,PyWrap
试图导入命令行所包括的模块。然后PyWrap
在模块中寻找wx.App
的子类,并创建子类的一个实例。之后,PyWrap
创建一个带有shell
的wx.py.crust.CrustFrame
窗口,把这个应用程序对象显示在PyCrust
的名字空间树中,并且启动 wxPython
事件循环。
PyWrap
的源码显示在例子4.3中。它显示了如何用少量的代码将大量的功能增加到你的程序中。
例4.3
"""PyWrap is a command line utility that runs a python
program with additional runtime tools, such as PyCrust."""
__author__ = "Patrick K. O'Brien [email protected] "
__cvsid__ = "$Id: PyCrust.txt,v 1.15 2005/03/29 23:39:27 robind Exp $"
__revision__ = "$Revision: 1.15 $"[11:-2]
import os
import sys
import wx
from wx.py.crust import CrustFrame
def wrap(app):
wx.InitAllImageHandlers()
frame = CrustFrame()
frame.SetSize((750, 525))
frame.Show(True)
frame.shell.interp.locals['app'] = app
app.MainLoop()
def main(modulename=None):
sys.path.insert(0, os.curdir)
if not modulename:
if len(sys.argv) 2:
print "Please specify a module name."
raise SystemExit
modulename = sys.argv[1]
if modulename.endswith('.py'):
modulename = modulename[:-3]
module = __import__(modulename)
# Find the App class.
App = None
d = module.__dict__
for item in d.keys():
try:
if issubclass(d[item], wx.App):
App = d[item]
except (NameError, TypeError):
pass
if App is None:
print "No App class was found."
raise SystemExit
app = App()
wrap(app)
if __name__ == '__main__':
main()
运行了PyWrap
命令之后,来自spare
的简单的框架(frame)
和PyCrust
的框架都显示出来。
PyCrust
in
action
现在让我们看看,在PyCrust
shell
中我们对spare.py
应用程序框架做些什么。图4.10显示了这个结果。我们将通过导入wx
和增加一个画板到我们的框架作为开始:
import wx
app.frame.panel = wx.Panel(parent=app.frame)
app.frame.panel.SetBackgroundColour('White')
True
图4.10
增加到框架的画板开始时是默认的银灰色,然后它被改变到白色。然而,设置画板背景色不立即改变它的显示。这需要去触发一个事件来导致画板重绘,以使用它的新颜色属性。一个触发这样事件的方法是要求画板刷新自身:
app.frame.panel.Refresh()
现在一个白色的画板显示了,我们对于理解wxPython
如何工作的细节又进了一步。
接下来,让我们增加一个状态栏:
app.frame.statusbar = app.frame.CreateStatusBar(number=3)
app.frame.statusbar.SetStatusText("Left", 0)
app.frame.statusbar.SetStatusText("Center", 1)
app.frame.statusbar.SetStatusText("Right", 2)
注意在不改变这个框架的尺寸情况下,这个状态栏在这个框架中是如何显示的。也要注意添加到三个状态栏中的文本的立即显示了出来,而不要求刷新。现在让我们增加一个菜单和一个菜单栏:
app.frame.menubar = wx.MenuBar()
menu = wx.Menu()
app.frame.menubar.Append(menu, "Primary")
app.frame.SetMenuBar(app.frame.menubar)
menu.Append(wx.NewId(), "One", "First menu item")
menu.Append(wx.NewId(), "Two", "Second menu item")
当你在PyCrust
shell
中处理你自己的wxPython
对象时,注意改变对你正在运行的程序的影响。试试回答后面的问题。在框架中菜单何时才实际显示出来的?在程序运行的时候,你能改变菜单的哪些属性?你能够让它们无效吗?交互地探究这些可以帮助你更好的理解wxPython
,同时当你写真实的代码时给你带来更大的自信。
到目前,我们已经花了很多节讨论PyCrust
,我们下面准备看一看Py
包的其余的东西。
在Py包中还有其它什么?
所有PyCrust
中的程序都利用了Py
包中的Python
模块,诸如shell.py
,crust.py
,introspect.py
和 interpreter.py
。这些程序是用来做PyCrust
的建造块,你可以分别或一起使用它们。
PyCrust
代表了组装包含在Py
包中功能模块的一各方法。PyShell
是另一方法,PyAlaMode
是第三种。在这 些方法中,它们的底层代码大多数是相同的,只是外包装有所变化而已。因此,你可以把Py
当做一个模块 库,你可以随意地在你的程序中的任何地方组装其中的模块,用来显示一个wxPython
shell
、一个代码编 辑器或运行时内省信息。
在Py
包中,提供给用户界面功能的模块和没有这功能的模块有明显的区别。这个区别使得在你的程序中很 容易使用这些模块。以Py
开头的模块是终端用户GUI
程序,如PyCrust
,PyShell
,PyAlaMode
和PyAlaCarte
。在你的程序中,你不会想导入这些模块。下节说明终端用户模块。
使用GUI程序工作
下表4.3说明了用户级程序。
PyAlaCarte
:简单的源代码编辑器。一次编辑一个文件。 PyAlaMode
:多文件源代码编辑器。每个文件分别显示在一个notebook
标签中。第一个标签包含一个PyCrust
分隔窗口。 PyCrust
:合并了wxPython
shell
和notebook
标签,notebook
包含一个名字空间树查看器。 PyFilling
:简单的名字空间树查看器。这个程序自己不是很有用。它的存在只是作为如何使用底层库的一个例子。 PyShell
:简单的wxPython
shell
界面,没有PyCrust
中的notebook
。功能上,PyShell
中的wxPython
shell
和PyCrust
中的是一样的。 PyWrap
:命令行工具,用以运行一个存在的程序和PyCrust
框架,让你能够在PyCrust
shell
中处理这个应用程序。
使用支持模块工作
支持模块为终端用户提供了基本的功能,可以被导入你的程序中。这些模块是用来创建用户级Py
程序的建
造块。下表4.4列出了这些支持模块,它们是Py
包的一部分,说明如下:
buffer
:支持文件编辑。 crust
:包含PyCrust
应用程序独有的GUI
元素。 dispatcher
:提供全局信号分派服务。 document
:document
模块包含一个非常简单的Document
类,这个类是一个小的文件类。document
跟踪不同的文件属性,如名字和路径,并提供read()
和write()
方法。Buffer
类委托这些低级的读写操作给一个Document
实例。 editor
:包含所有显示在PyAlaCarte
和PyAlaMode
程序中的GUI
编辑部分。 editwindow
:这个editwindow
模块包含了一个简单的EditWindow
类。这个类继承自wx.stc.StyledTextCtrl
(STC)
,并且提供了Py
包中的STC
的三种主要用法的所有共同的特性,这三种主要用法是:作为一个Python
shell
,作为一个源代码编辑器和作为一个只读源码显示器。 filling
:包含所有的GUI
控件,这些GUI
控件让用户能够浏览对象名字空间并显示那些对象运行时的信息。 frame
:frame
模块定义了一个Frame
类,这个Frame
类是Py
包中所有其它frames
的基类。菜单项根据当前状态和上下文不断地自我更新。 images
:images
模块包含被不同Py
程序使用的图标。 interpreter
:Interpreter
类负责提供自动完成列表,调用提示信息等。 introspect
:为一些方面提供多种内省类型,像调用提示和命令自动完成。 pseudo
:这个模块定义文件类类,文件类允许Interpreter
类去重定向stdin
,stdout
,stderr
。 shell
:这个模块包含GUI
元素,这些GUI
元素定义显示在PyCrust
,PyShell
和PyAlaMode
中的Python
shell
的界面。 version
:这个模块包含一个名为VERSION
的字符串变量,VERSION
代表Py
当前的版本。
下面我们讨论更复杂的模块。
buffer
模块
buffer
模块包含一个Buffer
类,这个类支持文件的通常编辑。buffer
有一些方法,例如new()
, open()
, hasChanged()
, save()
,和saveAs()
。文件操作基于buffer
所委托的Document
类的实例,Document
类定义在document
模块中。文件内容的实际编辑是通过Editor
类的一个或多个实例发生的,Editor
类定义在 editor
模块中。buffer
扮演一个在一个或多个编辑器和实际物理文件之间的中间人。
Buffer
类的一个独特的手法是每个buffer
实例都分配了它自己的Python
解释器实例。这个特点使得buffer
能够被用在那些当编辑Python
源代码文件时需要提供自动完成,调用提示和其它运行时帮助的应用程序中 。每个buffer
解释器都是完全独立的,并且在buffer
的updateNamespace()
方法被调用时更新。下例4.4显示了updateNamespace()
方法的源代码。
例4.4
def updateNamespace(self):
"""Update the namespace for autocompletion and calltips.
Return True #if updated, False if there was an error."""
if not self.interp o not hasattr(self.editor, 'getText'):
return False
syspath = sys.path
sys.path = self.syspath
text = self.editor.getText()
text = text.replace('\r\n', '\n')
text = text.replace('\r', '\n')
name = self.modulename o self.name
module = imp.new_module(name)
newspace = module.__dict__.copy()
try:
try:
code = compile(text, name, 'exec')
except:
raise
try:
exec code in newspace
except:
raise
else:
# No problems, so update the namespace.
self.interp.locals.clear()
self.interp.locals.update(newspace)
return True
finally:
sys.path = syspath
for m in sys.modules.keys():
if m not in self.modules:
del sys.modules[m]
这个方法使用Python
内建的compile
方法编译编辑器中的文本,然后使用关键词exec
来执行。如果编译成 功,将放置若干变量到newspace
名字空间中。通过用执行的结果重置解释器的局部名字空间,解释器支持 访问定义在编辑器的buffer
中的任何类,方法或变量。
crust
模块
crust
模块包含6个GUI
元素,它们专门用于PyCrust
应用程序的。这最常用的类是CrustFrame
,它是wx.Frame
的子类。如果你再看一下例4.3,你能看到PyWrap
程序是如何导入CrustFrame
并创建其一个实例的。这是嵌入一个PyCrust
框架到你自己的程序中的最简单的方法。如果你想要比一个完整的框架更小的东西,你可以使用下表4.5所列的一个或多个类。
表4.5
Crust
:基于wx.SplitterWindow
并包含一个shell
和带有运行时信息的notebook
。 Display
:样式文本控件,使用Pretty
Print
显示一个对象。 Calltip
:文本控件,包含最近shell
调用帮助。 SessionListing
:文本控件,包含关于一个会话的所有命令。 DispatcherListing
:文本控件,包含关于一个会话的所有分派。 CrustFrame
:一个框架,包含一个Crust
分隔窗口。
这些GUI
元素可以被用在任何wxPython
程序中,以提供有用的可视化内省。
dispatcher
模块
dispatcher
提供了全局信号分派服务。那意味它扮演着一个中间人,使得对象能够发送和接受消息,而无须知道彼此。所有它们需要知道的是这个正在发送的信号(通常是一个简单的字符串)。一个或多个对象可以要求这个dispatcher
,当信号已发出时去通知它们,并且一个或多个对象可以告诉这个dispatcher
去发送特殊的信号。
下例4.5是关于为什么dispatcher
是如此有用的一个例子。因为所有的Py
程序都是建造在相同的底层模块之上的,所以PyCrust
和PyShell
使用几乎相同的代码。这唯一的不同是,PyCrust
包括了一个带有额外功能的notebook
,如名字空间树查看器,当命令被发送到解释器时,名字空间树查看器更新。在一个命令通过解释器时,解释器使用dispatcher
发送一个信号:
例4.5 经由dispatcher
模块来发送命令的代码
def push(self, command):
"""Send command to the interpreter to be executed.
Because this may be called recursively, we append a new list
onto the commandBuffer list and then append commands into
that. If the passed in command is part of a multi-line
command we keep appending the pieces to the last list in
commandBuffer until we have a complete command. If not, we
delete that last list."""
command = str(command) # In case the command is unicode.
if not self.more:
try:
del self.commandBuffer[-1]
except IndexError:
pass
if not self.more:
self.commandBuffer.append([])
self.commandBuffer[-1].append(command)
source = '\n'.join(self.commandBuffer[-1])
more = self.more = self.runsource(source)
dispatcher.send(signal='Interpreter.push', sender=self,
command=command, more=more, source=source)
return more
crust
中的各有关部分和filling
模块在它们的构造器中通过连接到dispatcher
,自己作为信号的接受器。下例4.6显示了关于出现在PyCrust
的Session
标签中的SessionListing
控件的源码:
例4.6 PyCrust
session
标签的代码
class SessionListing(wx.TextCtrl):
"""Text control containing all commands for session."""
def __init__(self, parent=None, id=-1):
style = (wx.TE_MULTILINE | wx.TE_READONLY |wx.TE_RICH2 | wx.TE_DONTWRAP)
wx.TextCtrl.__init__(self, parent, id, style=style)
dispatcher.connect(receiver=self.push,signal='Interpreter.push')
def push(self, command, more):
"""Receiver for Interpreter.push signal."""
if command and not more:
self.SetInsertionPointEnd()
start, end = self.GetSelection()
if start != end:
self.SetSelection(0, 0)
self.AppendText(command + '\n')
注意SessionListing
的接受器(push()
方法)是如何忽略由解释器发送来的sender
和source
参数的。dispatcher
非常灵活,并且只发送接受器能接受的参数。
editor
模块
editor
模块包含了出现在PyAlaCarte
和PyAlaMode
程序中的所有GUI
编辑组件。如果你愿意在你的程序中包括一个Python
源代码编辑器,那么使用在下表4.6中所说明的类。
这些类可以被使用在任何程序中以提供有用的代码风格编辑功能。
表4.6 定义在editor
模块中的类
EditerFrame
:被PyAlaCarte
用来支持一次一个文件的编辑。EditerFrame
是来自frame
模块的较一般的Frame
类的子类。 EditorNotebookFrame
:EditerFrame
的子类,它通过增加一个notebook
界面和同时编辑多个文件的能力扩展了EditerFrame
。它是一个被PyAlaMode
使用的frame
类。 EditorNotebook
:这个控件被EditorNotebookFrame
用来在各自的标签中显示各自的文件。 Editor
:管理一个buffer
和与之相关的EditWindow
之间的关联。 EditWindow
:基于StyledTextCtrl
的文本编辑控件。
filling
模块
filling
模块包含所有使用户能够浏览对象的名字空间和显示关于那些对象的运行时信息的GUI
控件。 定义在filling
模块中的四个类的说明见下表4.7
表4.7
FillingTree
:基于wx.TreeCtrl
,FillingTree
提供对象名字空间的分级树。 FillingText
:editwindow.EditWindow
的子类,用以显示当前在FillingTree
所选择的对象的细节。 Filling
:一个wx.SplitterWindow
,它的左边包括一个FillingTree
,右边包括一个FillingText
。 FillingFrame
:一个包含Filling
分隔窗口的框架。双击filling
树中的一项将打开一个新的FillingFrame
,其中被选择的项作为树的根。
使用这些类,使你能够容量地创建Python
名字空间的分级树。如果你设置你的数据为Python
对象,这能够用作一个快速的数据浏览器。
interpreter
模块
interpreter
模块定义了一个Interpreter
类,基于Python
标准库中的code
模块的Interactive
- Interpreter
类。除了负责发送源代码给Python
外,Interpreter
类还负责提供自动完成列表,调用提示信息和甚至触发自动完成特性的关键码(通常是".")。
由于这清楚的责任划分,你可以创建你自己的Interpreter
的子类并传递其一个实例到PyCrust
shell
,从而代替默认的interpreter
。这已经应用到了一些程序中以支持自定义评议种类,而仍然利用PyCrust
环境。
introspect
模块
introspect
模块被Interpreter
和FillingTree
类使用。它为调用提示和命令自动完成提供了多种内省类型支持功能。下面显示了wx.py.introspect
的用法,它得到一个列表对象的所有属性的名字,排除了那些以双下划线开始的属性:
import wx
L = [1, 2, 3]
wx.py.introspect.getAttributeNames(L, includeDouble=False)
['append', 'count', 'extend', 'index', 'insert', 'pop',
'remove', 'reverse', 'sort']
getAttributeNames()
函数被FillingTree
类使用以生成它的名字空间分级。理解内省模块的最好方法是关注单元测试。查看你的Python
安装目录的Lib
/site
-packages
/wx
/py
/tests
中的test_introspect.py
文件。
shell
模块
shell
模块包含出现在PyCrust
, PyShell
, 和PyAlaMode
定义Python
shell
界面的GUI
元素。下表4.8提供了每个元素的说明。这最常用的类是ShellFrame
,它是frame.Frame
的子类。它包含一个Shell
类的实例,Shell
类处理提供交互Python
环境的大部分工作。
表4.8 定义在shell
模块中的类
Shell
:Python
shell
基于wx.stc.StyleTextCtrl
。Shell
子类化editwindow.EditWindow
,然后使底层的文本控件的行为像一具Python
shell
,而非一个源码文件编辑器。 ShellFacade
:简化的与所有shell
相关的功能的接口。它是半透明的,它仍然是可访问的,尽管只有一些是对shell
用户可见的。 ShellFrame
:一个包含一个Shell
窗口的框架。
ShellFacade
类在PyCrust
的开发期间被创建,它作为在shell
中访问shell
对象自身时去简化事情的一个方法。当你启动PyCrust
或PyShell
时,Shell
类的实例在Python
shell
中的有效的。例如,你可以在shell
提示符下调用shell
的about()
方法,如下所示:
shell.about()
Author: "Patrick K. O'Brien [email protected] "
Py Version: 0.9.4
Py Shell Revision: 1.7
Py Interpreter Revision: 1.5
Python Version: 2.3.3
wxPython Version: 2.4.1.0p7
Platform: linux2
由于Shell
继承自StyledTextCtrl
,所以它包含超过600个属性。大部分属性对shell
提示符是没用的,因此,ShellFacade
被创建来限制当你进入shell
时出现在自动完成列表中的属性的数量。目前,shell
对象只显示最有用的shell
属性的25个。
如何在wxPython中使用Py包中的模块?
如果你不想在你的应用程序使用一个完整的PyCrust
框架,那么该怎么做呢?如果你在一个框架中仅仅只想要shell
界面,而在另一个框架中要一个名字空间查看器,该怎么办呢?如果你想把它们永久添加到你的程序中以该怎么办呢?这些方案不仅是可能的,而且也是十分简单的。我们将用一个例子来说明这该怎么做来结束本章。
我们将再看一下在第2章中所创建的程序,它带有一个菜单栏,工具栏和状态栏。我们将添加一个菜单,它的一个菜单项用以显示一个shell
框架,另一个用来显示一个filling
框架。最后我们将把filling
树的根设置给我们的主程序的框架对象。结果显示在图4.11中。
图4.11
下例4.7显示了修改过的源码。正如你的看到的,我们只增加了几行就实现了所要求的功能。
例4.7
#!/usr/bin/env python
import wx
#1 导入这些框架类
from wx.py.shell import ShellFrame
from wx.py.filling import FillingFrame
import images
class ToolbarFrame(wx.Frame):
def __init__(self, parent, id):
wx.Frame.__init__(self, parent, id, 'Toolbars',size=(300, 200))
panel = wx.Panel(self, -1)
panel.SetBackgroundColour('White')
statusBar = self.CreateStatusBar()
toolbar = self.CreateToolBar()
toolbar.AddSimpleTool(wx.NewId(), images.getNewBitmap(),"New", "Long help for 'New'")
toolbar.Realize()
menuBar = wx.MenuBar()
menu1 = wx.Menu()
menuBar.Append(menu1, " ")
menu2 = wx.Menu()
menu2.Append(wx.NewId(), " ", "Copy in status bar")
menu2.Append(wx.NewId(), "C ", "")
menu2.Append(wx.NewId(), "Paste", "")
menu2.AppendSeparator()
menu2.Append(wx.NewId(), " ", "Display Options")
menuBar.Append(menu2, " ")#2 创建Debug菜单及其菜单项
menu3 = wx.Menu()
shell = menu3.Append(-1, " shell","Open wxPython shell frame")
filling = menu3.Append(-1, " viewer","Open namespace viewer frame")
menuBar.Append(menu3, " ")#3 设置菜单的事件处理器
self.Bind(wx.EVT_MENU, self.OnShell, shell)
self.Bind(wx.EVT_MENU, self.OnFilling, filling)
self.SetMenuBar(menuBar)
def OnCloseMe(self, event):
self.Close(True)
def OnCloseWindow(self, event):
self.Destroy() #4 OnShell菜单项和OnFilling菜单项处理器
def OnShell(self, event):
frame = ShellFrame(parent=self)
frame.Show()
def OnFilling(self, event):
frame = FillingFrame(parent=self)
frame.Show()
if __name__ == '__main__':
app = wx.PySimpleApp()
app.frame = ToolbarFrame(parent=None, id=-1)
app.frame.Show()
app.MainLoop()
说明:
#1 这里我们导入了ShellFrame
和FillingFrame
类 #2 我们添加了第三个菜单Debug
到框架的菜单栏 #3 绑定一个函数给wx.EVT_MENU()
,使我们能够将一个处理器与菜单项关联,以便当这个菜单项被选择时调用所关联的处理器。 #4 当用户从Debug
菜单中选择Python
shell
时,shell
框架被创建,它的双亲是工具栏框架。当工具栏框架被关闭时,任何打开的shell
或filling
框架也被关闭。
本章小结
1、像wxPython
这样的工具包本身是大而复杂的。GUI
控件之间的交互并不总是直观的,整个的处理决定于事件并响应于事件,而非一个线性的执行序列。使用如PyCrust
shell
能够很大程度上提高你对事件驱动环境的理解。
2、PyCrust
仅仅是另一个Python
shell
,它类似于IDLE
, Boa
Constructor
, PythonWin
和其它开发工具所包括的shell
。然而,PyCrust
是用wxPython
创建的,当你使用wxPython
开发程序时,它是很有用的。尤其是,你不会有任何事件循环冲突方面的问题,并且你可以在PyCrust
的shell
和名字空间查看器中处理你的程序运行时的所有方面。
3、由于PyCrust
是wxPython
发行版的一部分,所以它随同wxPython
一同被安装,包括了所有的源码。这使得PyCrust
容易使用,并且减少了摸清如何在你自己的程序中提供内省功能的学习曲线。
4、另外,Py
包的模块化的设计,使你很容易去挑选最有益于你程序的模块,如源代码编辑、名字空间查看、或shell
5、PyCrust
减少了wxPython
学习的曲线,并帮助你掌握你的程序运行时的细微之处。
下一章,我们将应用我们所学到的关于wxPython
方面的知识,并且提供一些关于如何组织你的GUI
程序的实用的建议。