GUI programming with wxPython 之 XRC

前言:

我是在豆瓣评论(http://book.douban.com/review/5780362/)上看得连接(http://hwg86.blog.163.com/blog/static/6558691020101279463670/),但这个连接失效了.后百度到http://madrigar.blog.163.com/blog/static/339503932009758512446/是分为4个部分,为了方便,我合并转/收藏在此, 谢谢该文原创者,和以上分享者.

 

一、概念

XRC(XML Resource)的设计来源于wxWidgets,它的想法很简单,就是将界面设计的工作从程序中独立出来。具体的做法是,创建单独的XML文件,负责界面设计,程序运行的时候载入,生成界面。这样做的好处是显而易见的。首先,将繁琐的外观设计代码从程序中去掉,程序更清晰易读。其次,XRC文件独立于程序,程序运行时才调用,因此可以随意更换外观。这种思想并不是wxWidgets的原创,MFC中的RC已经有了,类似的还有HTML和CSS的关系。wxPython从wxWidgets继承而来,当然也保留了XRC。

这里有几点要补充的。一是wxPython的XRC文件中用到的类名称仍然是wxWidgets中的类名称,换句话说,wxPython和wxWidgets可以共用XRC文件,第二点要补充的是XRC文件可以编译成二进制文件XRS,或者编译成C++代码。

二、例子

先来看一个例子。

import wx

class MyFrame(wx.Frame):

    def __init__(self):

        wx.Frame.__init__(self, parent=None, id=wx.ID_ANY, title='My Frame')

        panel = wx.Panel(self)

        label1 = wx.StaticText(panel, wx.ID_ANY, 'First name:')

        label2 = wx.StaticText(panel, wx.ID_ANY, 'Last name:')

        self.text1 = wx.TextCtrl(panel, wx.ID_ANY)

        self.text2 = wx.TextCtrl(panel, wx.ID_ANY)

        button = wx.Button(panel, wx.ID_ANY, 'Submit')

        sizer = wx.FlexGridSizer(rows=2, cols=2, vgap=5, hgap=5)

        self.Bind(wx.EVT_BUTTON, self.OnSubmit, button)

        sizer.Add(label1)

        sizer.Add(self.text1)

        sizer.Add(label2)

        sizer.Add(self.text2)

        sizer.Add((0,0)) #filler for the grid cell

        sizer.Add(button)

        panel.SetSizer(sizer)

        sizer.Fit(self)

    def OnSubmit(self, evt):

        wx.MessageBox('Your name is %s %s!' %

(self.text1.GetValue(), self.text2.GetValue()), 'Feedback')

class MyApp(wx.App):

    def OnInit(self):

        frame = MyFrame()

        self.SetTopWindow(frame)

        frame.Show()

        return True

if __name__ == '__main__':

    app = MyApp(False)

    app.MainLoop()

这是一个简单的wxPython程序。可以看到上面的代码中,除了Bind和OnSubmit,其他的代码都是和界面设计有关的,这些代码或者类似的代码出现于几乎所有的GUI程序中。下面是用XRC重新实现的代码。

import wx

from wx import xrc

class MyApp(wx.App):

    def OnInit(self):

        self.res = xrc.XmlResource('gui.xrc')

        self.init_frame()

        return True

    def init_frame(self):

        self.frame = self.res.LoadFrame(None, 'mainFrame')

        self.panel = xrc.XRCCTRL(self.frame, 'panel')

        self.text1 = xrc.XRCCTRL(self.panel, 'text1')

        self.text2 = xrc.XRCCTRL(self.panel, 'text2')

        self.frame.Bind(wx.EVT_BUTTON, self.OnSubmit, id=xrc.XRCID('button'))

        self.frame.Show()

    def OnSubmit(self, evt):

        wx.MessageBox('Your name is %s %s!' %

(self.text1.GetValue(), self.text2.GetValue()), 'Feedback')

if __name__ == '__main__':

    app = MyApp(False)

    app.MainLoop()

看起来是不是比上面的清晰多了,当然,程序要跑起来,还需要下面的部分.

下面的代码属于XRC文件。

<?xml version="1.0" encoding="utf-8"?>

<resource>

    <object name="mainFrame">

        <title>My Frame</title>

        <object name="panel">

            <object

                <cols>2</cols>

                <rows>3</rows>

                <vgap>5</vgap>

                <hgap>5</hgap>

                <object

                    <object name="label1">

                        <label>First name:</label>

                    </object>

                </object>

                <object

                    <object name="text1"/>

                </object>

                <object

                    <object name="label2">

                        <label>Last name:</label>

                    </object>

                </object>

                <object

                    <object name="text2"/>

                </object>

                <object

                    <size>0,0</size>

                </object>

                <object

                    <object name="button">

                        <label>Submit</label>

                    </object>

                </object>

            </object>

        </object>

    </object>

</resource>

这段代码看起来很复杂,但是如果熟悉XML的话,应该很容易看明白它的结构。最关键的是,我们不用亲手写这些代码,很多工具,像XRCedwxGlade都可以自动生成这些代码,你所要做的只是点几下鼠标。

三、创建XRC文件

虽然我们不用亲自写XRC文件,弄清楚它的原理还是必要的。在wxPython中,Button的构造函数是这样的。

wx.Button( parent, id, label='', pos=wx.DefaultPosition, size=wx.DefaultSize,

size=wx.DefaultSize, style=0, validator=wx.DefaultValidator, name='button')

实际使用的时候,通常没有这么多参数,

button = wx.Button(panel, wx.ID_ANY, 'Submit')

但是在XRC文件中,要创建一个Button,通常用下面的方式,

<object name="button">

<label>Submit</label>

</object>

从上面这几行代码中,我们可以得到如下信息:

1. XRC<object> </object>表示要创建的对象。

2. XRC用所用的是C++的类名wxButton,而不是wxPython的类名wx.Button

3. XRCname表示对象的名称,对应于python代码中的id

4. XRC用层次关系表示对象之间的父子关系。

 

下面这段代码显示了XRC文件的层次关系。

<?xml version="1.0" encoding="utf-8"?>

<resource>

    <object name="mainFrame">

        <title>Test Frame</title>

        <object name="panel">

            <object name="button">

                <label>Submit</label>

            </object>

        </object>

    </object>

</resource>

注意,所有的结构都包含在<resource> </resource>中,表示这个文件是XML Resource文件。

到目前为止,我们对XRC文件的结构已经有了初步的认识,接下来要了解的是在Python程序中如何用到它们。

四、使用XRC文件

如何使用XRC文件是wxPython+XRC框架的关键一步。在前面的代码中,我们注意到这样两行,

import wx

from wx import xrc

这里要强调的是xrc模块必须单独被导入,所以,第二行是必须的。

class MyApp(wx.App):

def OnInit(self):

self.res = xrc.XmlResource('gui.xrc')

self.init_frame()

return True

在上面这几行代码中,在上面的代码中,Self.res存储xrc文件的内容。xrc.XmlResource是导入XRC文件,创建xrc对象的关键。

self.init_frame()是用户自己定义的函数。你不一定要定义self.init_frame()函数,这样做的好处只是把初始化框架的工作单独放在一起,看起来清晰。你也可以在OnInit函数中完成所有Frame的初始化工作。下面我们来看init_frame()函数中做了什么,

self.frame = self.res.LoadFrame(None, 'mainFrame')

LoadFrame()函数返回mainFrame的引用,将顶层Frame对象载入到python程序中,第一个参数是parent,第二个参数是ID,即XRC文件中为Frame取的名字。这个函数还初始化所有的children Frame,这些工作并没有显示的表现出来,由XRC自动完成。

当你想从XRC文件中提取信息时,有两种方式可以选择,一种是XRCID(XRC_name),这个函数可以获得对象的ID;另一种是XRCCTRL(XRC_name),可以获得对象的引用。

self.panel = xrc.XRCCTRL(self.frame, 'panel')

self.text1 = xrc.XRCCTRL(self.panel, 'text1')

self.text2 = xrc.XRCCTRL(self.panel, 'text2')

XRCCTRL需要多说两句,XRCCTRL函数返回对象的引用。但是并没有create新对象,仅仅是获取他们的引用,创建对象的工作已经在上面的LoadFrame()过程中完成了。另一个需要强调的是,调用XRCCTRL时,不一定提供直接的parent,可以使用更上一层的parentXRCCTRL会用FindWindowById递归的往下找。也就是说,如果你迷路了,报上爷爷的名字,警察叔叔也能把你送到家。

到目前为止,构造界面的工作算是完成了。如果你熟悉GUI编程的话,马上会想到,接下来的工作应该是将Gui对象,事件和事件处理函数联系起来。这就是接下来要讲的事件绑定。

五、事件绑定

先看一段代码,

self.frame.Bind( wx.EVT_BUTTON, self.OnSubmit, id=xrc.XRCID('button') )

这是一个简单的绑定的例子,将按钮事件,事件函数和按钮ID绑定起来。前两个参数不用多解释,注意第三个参数中的XRCID函数,这个函数通过对象的名称ID返回对象的数字ID。这个数字ID是你在创建对象的时候wxPythonwx.NewID()生成的。

讲到这里有必要了解一下Bind()函数,下面是Bind()函数的定义,

Bind(event, handler, source=None, id=wx.ID_ANY, id2=wx.ID_ANY)

最后一个参数我们忽略不计。第四个参数就是我们刚才的例子中的第三个参数,你也许会奇怪,为什么跳过了默认的第三个参数直接读取第四个参数,程序还能正常?在这种情形下,它的确就是正常。看了Bind()函数的定义之后,你也许还能想出另一种调用方法,像下面这样,

self.button = xrc.XRCCTRL(self.panel, 'button')

self.frame.Bind(wx.EVT_BUTTON, self.OnSubmit, self.button)

这当然也是正确的。但我们通常都用前一种方法。为什么呢?后一种不是更直观吗?真正的原因是,XRCCTRL只能返回wxWindow的继承类的引用,也就是有GetID方法的类。但很多情况下,我们要绑定的对象并不是wxWindow的继承类,像我们经常用到的Bind是将event handlermenu绑定起来,wxMenuItem类不是由wxWindow继承而来,因此,用XRCCTRL得不到它的引用,这种情况下,必须用XRCID来获得对象的ID,并将ID传给Bind作为参数。所以,为了简单,为了统一,我们就选择ID来作为Bind的参数。

关于利用wxPython+XRC的框架进行GUI编程,到这里就讲完了,这些东西是我从网上收集来的,半翻译半笔记最后写成现在这样。主要参考了下面这篇文章

http://wiki.wxpython.org/XRCTutorial

希望能对也为这个内容困惑的朋友有帮助。

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
学习使用Python的GUI编程需要掌握许多技巧和概念。Python是一种流行的编程语言,可以用于开发各种图形用户界面(GUI)应用程序。通过掌握GUI编程,可以创建具有交互性和视觉吸引力的应用程序。 首先,需要了解GUI编程的基本概念和术语。例如,掌握窗口、按钮、文本框、标签等常见GUI组件的操作方法和属性。还需要理解事件驱动编程模型,理解事件处理器以及如何响应用户的输入。 其次,需要熟悉Python的GUI编程框架,例如Tkinter、PyQt和wxPython等。这些框架提供了各种GUI组件和工具,使得开发GUI应用程序变得更加简单和快捷。通过阅读文档和例子,可以掌握这些框架的基本用法和常见的GUI编程模式。 此外,学习GUI编程还需要了解布局管理器和图形化设计工具的使用。布局管理器能够帮助开发者自动定位和调整GUI组件的位置和大小,使得界面更加美观和灵活。图形化设计工具可以加速开发过程,通过可视化的方式设计和调整界面布局,省去手动编写代码的麻烦。 最重要的是不断实践和积累经验。通过编写小型的GUI应用程序,逐步掌握GUI编程的技巧和方法。可以尝试自己设计一些简单的应用,例如计算器、日历、图像处理工具等,以巩固所学的知识。 总的来说,掌握Python的GUI编程需要学习基本概念和术语、熟悉GUI编程框架和工具,以及不断实践和积累经验。随着时间的推移,开发者将逐渐成为GUI编程的大师,并能够设计和开发出高质量的用户界面应用程序。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值