注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

风雨启示录

欢迎光临我的网店优优我心:http://uumyheart.taobao.com

 
 
 

日志

 
 

wxPython in Action (二)  

2008-07-26 15:13:19|  分类: python学习笔记 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
第二章 给你的wxPython程序一个稳固的基础

房屋的基础是混凝土结构,它为其余的建造提供了坚固的 基础。你的wxPython程序同样有一个基础,它由两个必要的对象组成,用于支持你的应用程序的其余部分。它们是应用程序对象和顶级窗口对象。适当地使 用这两个对象将给你的wxPython应用程序一个稳固的开始并使得构造你的应用程序的其余部分更容易。


2.1 关于所要求的对象我们需要知道些什么?

让我们来说明一下这两个基础对象。这个应用程序对象管理主事件循环,主事件循环是你的wxPython程序的动力。启动主事件循环是应用程序对象的工作。没有应用程序对象,你的wxPython应用程序将不能运行。
顶级窗口通常管理最重要的数据,控制并呈现给用户。例如,在词处理程序中,主窗口是文档的显示部分,并很可能管理着该文档的一些数据。类似地,你的web浏览器的主窗口同时显示你所关注的页面并把该页作为一个数据对象管理。
下图显示了这两个基础对象和你的应用程序的其它部分这间的关系:


如图所示,这个应用程序对象拥有顶级窗口和主事件循环。顶级窗口管理其窗口中的组件和其它的你分配给它的数据对象。窗口和它的组件的触发事件基于用户的动作,并接受事件通知以便改变显示。


2.2 如何创建和使用一个应用程序对象?

任 何wxPython应用程序都需要一个应用程序对象。这个应用程序对象必须是类wx.App或其定制的子类的一个实例。应用程序对象的主要目的是管理幕后 的主事件循环。这个事件循环响应于窗口系统事件并分配它们给适当的事件处理器。这个应用程序对象对wxPython进程的管理如此的重要以至于在你的程序 没有实例化一个应用程序对象之前你不能创建任何的wxPython图形对象。

父类wx.App也定义了一些属性,它们对整个应用程序是全 局性的。很多时候,它们就是你对你的应用程序对象所需要的全部东西。假如你需要去管理另外的全局数据或连接(如一个数据库连接),你可以定制应用程序子 类。在某些情况下,你可能想为专门的错误或事件处理而扩展这个主事件循环。然而,默认的事件循环几乎适合所有的你所要写的wxPython应用程序。


2.2.1 创建一个wx.App的子类

创建你自己的wx.App的子类是很简单的。当你开始你的应用程序的时候,创建你自己的wx.App的子类通常是一个好的想法,即使是你不定制任何功能。创建和使用一个wx.App子类,你需要执行四个步骤:

1、定义这个子类
2、在定义的子类中写一个OnInit()方法
3、在你的程序的主要部分创建这个类的一个实例
4、调用应用程序实例的MainLoop()方法。这个方法将程序的控制权转交给wxPython

我 们在第一章中看到过OnInit()方法。它在应用程序开始时并在主事件循环开始前被wxPython系统调用。这个方法不要求参数并返回一个布尔值,如 果所返回的值是False,则应用程序将立即退出。大多数情况下,你将想要该方法返回的结果为真。处理某些错误条件,退出可能是恰当的方法,诸如所一个所 需的资源缺失。

由于OnInit()方法的存在,并且它是wxPython架构的一部分,所以任何关于你的定制的类的所需的初始化通常都 由OnInit()方法管理,而不在Python的__init__方法中。如果由于某些原因你决定需要__init__方法,那么你必须在你的 __init__方法中调用父类的__init__方法,如下所示:

wx.App.__init__(self)

通常,你在OnInit()方法中将至少创建一个框架对象,并调用该框架的Show()方法。你也可以有选择地通过调用SetTopWindow()方法来为应用程序指定一个框架作为顶级窗口。顶级窗口被作为那些没有指定父窗口的对话框的默认父窗口。

何时省略wx.App的子类

你没有必要创建你自己的wx.App子类,你通常想这样做是为了能够在OnInit()方法中创建你的顶级框架。
通常,如果在系统中只有一个框架的话,避免创建一个wx.App子类是一个好的主意。在这种情况下,wxPython提供了一个方便的类wx.PySimpleApp。这个类提供了一个最基本的OnInit()方法,wx.PySimpleApp类定义如下:

class PySimpleApp(wx.App):

    def __init__(self, redirect=False, filename=None,
                 useBestVisual=False, clearSigInt=True):
        wx.App.__init__(self, redirect, filename, useBestVisual,
                clearSigInt)

    def OnInit(self):
        return True

下面是wx.PySimpleApp一个简单用法:

if __name__ == '__main__':
    app = wx.PySimpleApp()
    frame = MyNewFrame(None)
    frame.Show(True)
    app.MainLoop()

在 上面这段代码的第一行,你创建了一个作为wx.PySimpleApp的实例的应用程序对象。由于我们在使用 wx.PySimpleApp类,所以我们 没有定制OnInit方法。第二行我们定义了一个没有父亲的框架,它是一个顶级的框架。(很显然,这个MyNewFrame类需要在别处被定义)这第三行 显示框架,最后一行调用应用程序主循环。

正如你所看到的,使用wx.PySimpleApp让你能够运行你的wxPython程序而无需创建你自己定制的应用程序类。如果你的应用程序十分简单的话,你应该只使用wx.PySimpleApp,且不需要任何其它的全局参数。


2.2.2 理解应用程序对象的生命周期

你 的wxPython应用程序对象的生命周期开始于应用程序实例被创建时,在最后一个应用程序窗口被关闭时结束。这个没有必要与你的wxPython应用程 序所在的Python脚本的开始和结束相对应。Python脚本可以在wxPython应用程序创建之前选择做一动作,并可以在wxPython应用程序 的MainLoop()退出后做一些清理工作。然而所有的wxPython动作必须在应用程序对象的生命周期中执行。正如我们曾提到过的,这意味你的主框 架对象在wx.App对象被创建之前不能被创建。(这就是为什么我们建议在OnInit()方法中创建顶级框架——因为这样一来,就确保了这个应用程序已 经存在。)

下图所示,创建应用程序对象触发OnInit()方法并允许新的窗口对象被创建。在OnInit()之后,这个脚本调用 MainLoop()方法,通知wxPython事件现在正在被处理。在窗口被关闭之前应用程序继续它的事件处理。当所有顶级窗口被关闭后, MainLoop()函数返回同时应用程序对象被注销。这之后,这个脚本能够关闭其它的可能存丰的连接或线程。
 


2.3 如何定向wxPython程序的输出?

所有的Python程序都能够通过两种标准流来输出文 本:分别是标准输出流sys.stdout和标准错误流sys.stderr。通常,Python脚本定向标准输出流到它所运行的控制台。然而,当你的应 用程序对象被创建时,你可以决定使用wxPython控制标准流并重定向输出到一个窗口。在Windows下,这个重定向行为是wxPython的默认行 为。而在Unix系统中,默认情况下,wxPython不控制这个标准流。在所有的系统中,当应用程序对象被创建的时候,重定向行为可以被明确地指定。我 们推荐利用这个特性并总是指定重定向行为来避免不同平台上的不同行为产生的任何问题。


2.3.1 重定向输出

如 果wxPython控制了标准流,那么经由任何方法发送到流的文本被重定向到一个wxPython的框架。在wxPyton应用程序开始之前或结束之后发 送到流的文本将按照Python通常的方法处理(输出到控制台)。下例同时演示了应用程序的生命周期和stdout/stderr重定向:

#!/usr/bin/env python

import wx
import sys

class Frame(wx.Frame):

    def __init__(self, parent, id, title):
        print "Frame __init__"
        wx.Frame.__init__(self, parent, id, title)

class App(wx.App):
   
    def __init__(self, redirect=True, filename=None):
        print "App __init__"  
        wx.App.__init__(self, redirect, filename)

    def OnInit(self):
        print "OnInit"    #输出到stdout
        self.frame = Frame(parent=None, id=-1, title='Startup')  #创建框架
        self.frame.Show()
        self.SetTopWindow(self.frame)
        print >> sys.stderr, "A pretend error message"    #输出到stderr
        return True

    def OnExit(self):
        print "OnExit"

if __name__ == '__main__':
    app = App(redirect=True) #1 文本重定向从这开始 
    print "before MainLoop"
    app.MainLoop()  #2 进入主事件循环  
    print "after MainLoop"

说明:

#1 这行创建了应用程序对象。这行之后,所有发送到stderr或stdout的文本都可被wxPython重定向到一个框架。参数redirect=True决定了是否重定向。

#2 运行的时候,应用程序创建了一个空的框架和也生成了一个用于重定向输出的框架。图示如下:

注意:stdout和stderr都定向到这个窗口。
当你运行了这个程序之后,你将会看到你的控制台有下面的输出:

App __init__
after MainLoop

这第一行在框架被打开之前生成,第二行在框架被关闭之后生成。
通过观察控制台和框架的输出,我们可以跟踪应用程序的生命周期。

下 面我们将上面的程序与图2.2作个比较,图中的"Start Script"对应于程序的 __main__语句。然后立即过渡到下一 “Application obect created",对应于程序的app = App(redirect=True)。应用程序实例的创建通过调用 wx.App.__init__()方法。然后是OnInit(),它被wxPython自动调用。从这里,程序跳转到 wx.Frame.__init__(),它是在wx.Frame被实例化时运行。最后控制转回到__main__语句,这里,MainLoop()被调 用,对应于图中的"MainLoop() called"。主循环结束后,wx.App.OnExit()被wxPython调用,对应于图中 “Application object destroyed”。然后脚本的其余部分完成处理。

为什么来自OnExit()的消息既没显示在窗口中也没显示在控制台中呢?其实它是在窗口关闭之前显示在wxPython的框架中,但窗口消失太快,所以无法被屏幕捕获。


2.3.2 修改默认的重定向行为

为 了修改这个行为,wxPython允许你在创建应用程序时设置两个参数。第一个参数是redirect,如果值为True,则重定向到框架,如果值为 False,则输出到控制台。如果参数redirect为True,那么第二个参数filename也能够被设置,这样的话,输出被重定向到 filename所指定的文件中而不定向到wxPython框架。因此,如果我们将上例中的app = App(redirect=True)改为 app = App(False),则输出将全部到控制台中:

App __init__
OnInit
Frame __init__
A pretend error message
before MainLoop
OnExit
after MainLoop

我们可以注意到OnExit()消息在这里显示出来了。
我们再作一个改变:
app = App(True, "output")

这将导致所有的应用程序创建后的输出重定向到名为output的文件中。而"App__init"和"after MainLoop"消息仍将发送到控制台,这是因为它们产生在wx.App对象控制流的时期之外。


2.4 如何关闭wxPython应用程序?

当你的应用程序的最后的顶级窗口被用户关闭时, wxPython应用程序就退出了。我们这里所说的顶层窗口是指任何没有父亲的框架,并不只是使用SetTopWindow()方法设计的框架。这包括任 何由wxPython自身创建的框架。在我们重定向的例子中,wxPython应用程序在主框架和输出重定向的框架都被关闭后退出,仅管只有主框架是使用 SetTopWindow()登记的,尽管应用程序没有明确地创建这个输出重定向框架。要使用编程触发一个关闭,你可以在所有的这里所谓顶级窗口上调用 Close()方法。
  评论这张
 
阅读(1466)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017