含有章节索引的中文 文章模板

::-- ehu4ever [DateTime(2005-08-07T05:40:51Z)] TableOfContents

1. PyGTK 2.0 Tutorial 中文编译

原作者:John Finlay

Version 2.4

April 13, 2005

1.1. 绪论

PyGTK 2.0 是一个系列的Python模块,它提供了一个使用 GTK+ 2.X 的接口。在本篇文档的其它部分中,PyGTK是指PyGTK的2.X版本,GTK 和 GTK+ 是指GTK+的2.X 版本。Python的门户是[http://www.pygtk.org www.pygtk.org]。PyGTK的主要作者是

who is assisted by the developers listed in the AUTHORS file in the PyGTK distribution and the PyGTK community.

Python is an extensible, object-oriented interpreted programming language which is provided with a rich set of modules providing access to a large number of operating system services, internet services (such as HTML, XML, FTP, etc.), graphics (including OpenGL, TK, etc.), string handling functions, mail services (IMAP, SMTP, POP3, etc.), multimedia (audio, JPEG) and cryptographic services. In addition there are many other modules available from third parties providing many other services. Python is licensed under terms similar to the LGPL license and is available for Linux, Unix , Windows and Macintosh operating systems. More information on Python is available at www.python.org . The primary Author of Python is:

GTK (GIMP Toolkit) is a library for creating graphical user interfaces. It is licensed using the LGPL license, so you can develop open software, free software, or even commercial non-free software using GTK without having to spend anything for licenses or royalties.

It's called the GIMP toolkit because it was originally written for developing the GNU Image Manipulation Program (GIMP), but GTK has now been used in a large number of software projects, including the GNU Network Object Model Environment (GNOME) project. GTK is built on top of GDK (GIMP Drawing Kit) which is basically a wrapper around the low-level functions for accessing the underlying windowing functions (Xlib in the case of the X windows system). The primary authors of GTK are:

GTK is currently maintained by:

GTK是一组面象的编程接口(API)。虽然它是用C语言写的,但是它在实现中遵循了“类”和“回调函数”的理念(pointers to functions)。

另外,还存在一个第三方的类,叫GLib,它包含的一些标准的calls,可以作为替代品。而且,GLib还包含了一些处理linked lists的函数,等等。这些可以作为替代的函数增强了GTK的可迁移性,因为GTK中的一些函数实现在另外一些类UNIX系统中是不标准或是没有的,比如g_strerror()。GLib还在一些地方对于libc版本的GTK更优秀,比如g_malloc有更强的可调试性。

在GLib的2.0版本中,使用了作为GTK类继承结构基础的类型系统,这个系统在GTK中使用广泛。有一个线程API,它抽象了各种系统平台的不同的本地线程API,而且还有loading modules的功能。

GTK使用Pango库来实现i18n的文本输出。

这篇文档描述了GTK+的Python接口,以GTK+2.0版本为基础。由Tony Gale和Ian Main编写。目地在于尽可能详细地描述PyGTK,但并不意味着是完美和完整。

这篇文档要求读者对于Python语言、和怎样编写和运行Python程序有一定的了解,如果你对于Python不是很熟,请先搞定[http://www.python.org/doc/current/tut/tut.html Python Tutorial]。这篇文档没有要求读者先前对GTK有了解,如果你是通过PyGTK来学习GTK,请说明你是怎样找到这篇文档的,以及你遇到什么样的困难。

这篇文档没有包括编译Python、GTK和GTK+的说明。

这篇文档以以下类库为基础:

This document is a "work in progress". Please look for updates on [http://www.pygtk.org www.pygtk.org].

I would very much like to hear of any problems you have learning PyGTK from this document, and would appreciate input as to how it may be improved. Please see the section on Contributing for further information. If you encounter bugs please file a bug at bugzilla.gnome.org against the pygtk project. The information at www.pygtk.org about Bugzilla may help.

The PyGTK 2.0 Reference Manual is available at http://www.pygtk.org/pygtkreference. It describes in detail the PyGTK classes.

The PyGTK website ([http://www.pygtk.org www.pygtk.org]) contains other resources useful for learning about PyGTK including a link to the extensive FAQ and other articles and tutorials and an active maillist and IRC channel (see [http://www.pygtk.org www.pygtk.org] for details).

1.1.1. 浅析PyGTK

这段没什么意思,就不麻烦了

1.2. Getting Started

我们用一段最最esay的代码来开始我们的PyGTK之旅,这个小程序会构造一个200x200 pixel的窗口,它只能用shell才能关掉。

   1 #!/usr/bin/env python
   2 
   3 # example base.py
   4 
   5 import pygtk
   6 pygtk.require('2.0')
   7 import gtk
   8 
   9 class Base:
  10     def __init__(self):
  11         self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
  12         self.window.show()
  13 
  14     def main(self):
  15         gtk.main()
  16 
  17 print __name__
  18 if __name__ == "__main__":
  19     base = Base()
  20     base.main()

将上面这段代码保存之后,就可以运行了:

python base.py

如果basy.py被你弄成了被执行文件,而且它的存放路径在PATH环境变量中 ,那么它也可以用下面这个命令运行:

base.py

下面是对于整段代码的解释:

第一行是调用python来执行base.py。第五到七行是用来区别装在你pc上的不同版本的PyGTK。这几行代码表明,本程序使用的是PyGTK的2.0版本,它包含了所有主版本号是2的PyGTK。这样这个程序就不会使用你pc上的PyGTK的早期版本(如果有的话)。

18到20行代码是用来检查name的值是不是main,这样就把程序限定在只有从python直接启动的情况下才会运行,而不是import到了一个正在运行的python解释器。在这种情况下,这上程序就会建造一个新的Base类,而且在 variable base中保存了一个指向它的reference(注意:其实这句话我也不是很懂!!!)。

程序的最后是调用main()启动GTK+的事件处理循环。

程序运用后,就会出现如下图的一个window:

Figure 2.1. Simple PyGTK Window

attachment:base.png

这个程序的第一行是用来可以让这个程序从*UNIX的shell程序中调用,当然python要在你的PATH中。在所有的程序中,如果有这么一行的话,它一定是line 1

程序的5到7行import了PyGTK 2的模块,并且初始化了GTK+的环境。这几个PyGTK的模块定义了用来操作GTK+的程序接口,这个程序中要用到。

对于熟悉GTK+的人来说,GTK+的初始化工作包括了调用gtk_init(),这个函数为我们事先搞定了一些事,比如默认的窗口视觉样式和颜色,默认的事件处理方式,它还检查了在命令行中传入我们程序的参数,查找一个或多个以下的东东:

它把它们从命令行中删除了(如果有的话),然后把余下的东西留给了我们的程序去对付。上面的那堆东西都是可以被GTK+程序处理的标准参数。

9到15行定义了一个python的类,它的名字叫作Base。在这个类中有实例初始化函数_init_()。这个_init_()定义了一个top-level的窗口(line 11),然后让GTK+显示它(line 12)。在11行中带有参数gtk.WINDOW_TOPLEVEL的函数gtk.Window()告诉窗口管理器:我们要这个窗口想要得到装修(使用一些窗口管理器的主题theme)和安置(放在显示平面的某一个位置)。这个窗口没有子窗口,它的默认大小是200x200,当然,我们可以在之后操作它。

14、15行定义main(),它调用了PyGTK的main()。而这个PyGTK的main()又去调用了GTK+的事件处理循环,来处理鼠标、键盘、和窗口事件。

18到20行让程序在被直接启动或是在被当作参数传入python解释器的情况下自动运行。在这些情况下,包含在python的变量_name_中的程序名称是_main_,这样18到20行程序就会被执行。

19行创建了一个Base类的实例,叫做base。一个gtk.Window被创建并且显示。

20行调用Base类的main()函数,启动GTK+的事件处理循环。当程序执行到这一步,GTK+会在sleep中等待X事件(比如键盘或鼠标上的键被按下),超时,或是文件的IO操作开始了。但是,在我们的这个最最easy的程序中,这些麻烦事都不去管了。

1.2.1. 用PyGTK说“Hello”

现在我们要写的这个程序会有一个按钮。这是PyGTK版本的“Hello World”。

   1 #!/usr/bin/env python
   2 
   3 # example helloworld.py
   4 
   5 import pygtk
   6 pygtk.require('2.0')
   7 import gtk
   8 
   9 class HelloWorld:
  10 
  11     # This is a callback function. The data arguments are ignored
  12     # in this example. More on callbacks below.
  13     def hello(self, widget, data=None):
  14         print "Hello World"
  15 
  16     def delete_event(self, widget, event, data=None):
  17         # If you return FALSE in the "delete_event" signal handler,
  18         # GTK will emit the "destroy" signal. Returning TRUE means
  19         # you don't want the window to be destroyed.
  20         # This is useful for popping up 'are you sure you want to quit?'
  21         # type dialogs.
  22         print "delete event occurred"
  23 
  24         # Change FALSE to TRUE and the main window will not be destroyed
  25         # with a "delete_event".
  26         return False
  27 
  28     def destroy(self, widget, data=None):
  29         print "destroy signal occurred"
  30         gtk.main_quit()
  31 
  32     def __init__(self):
  33         # create a new window
  34         self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
  35     
  36         # When the window is given the "delete_event" signal (this is given
  37         # by the window manager, usually by the "close" option, or on the
  38         # titlebar), we ask it to call the delete_event () function
  39         # as defined above. The data passed to the callback
  40         # function is NULL and is ignored in the callback function.
  41         self.window.connect("delete_event", self.delete_event)
  42     
  43         # Here we connect the "destroy" event to a signal handler.  
  44         # This event occurs when we call gtk_widget_destroy() on the window,
  45         # or if we return FALSE in the "delete_event" callback.
  46         self.window.connect("destroy", self.destroy)
  47     
  48         # Sets the border width of the window.
  49         self.window.set_border_width(10)
  50     
  51         # Creates a new button with the label "Hello World".
  52         self.button = gtk.Button("Hello World")
  53     
  54         # When the button receives the "clicked" signal, it will call the
  55         # function hello() passing it None as its argument.  The hello()
  56         # function is defined above.
  57         self.button.connect("clicked", self.hello, None)
  58     
  59         # This will cause the window to be destroyed by calling
  60         # gtk_widget_destroy(window) when "clicked".  Again, the destroy
  61         # signal could come from here, or the window manager.
  62         self.button.connect_object("clicked", gtk.Widget.destroy, self.window)
  63     
  64         # This packs the button into the window (a GTK container).
  65         self.window.add(self.button)
  66     
  67         # The final step is to display this newly created widget.
  68         self.button.show()
  69     
  70         # and the window
  71         self.window.show()
  72 
  73     def main(self):
  74         # All PyGTK applications must have a gtk.main(). Control ends here
  75         # and waits for an event to occur (like a key press or mouse event).
  76         gtk.main()
  77 
  78 # If the program is run directly or passed as an argument to the python
  79 # interpreter then create a HelloWorld instance and show it
  80 if __name__ == "__main__":
  81     hello = HelloWorld()
  82     hello.main()

下图是这个程序创建的窗口

Figure 2.2. Hello World Example Program

attachment:helloworld.png

在PyGTK的世界里,各种变量、函数的命名都有这样一个模式:gtk.*。 比如在上面这个程序中就有这些例子:

在之后的章节中可能不会显式地用出gtk这个前缀,但是它是默认的(不用担心)。上面的这个示例程序则使用了这个前缀。

1.2.2. 事件信号 和 函数调用的理论

Note
在GTK的2.0版本中,事件信号系统已经从GTK搬到了GLib。这其中眼花liao乱的细节咱就不管了,到时候再说吧。

在我们把helloworld.py详细解说一遍之前,我们有必要讨论一下事件信号 和 函数调用的概念。GTK+这个类库是遵循事件驱动理论的,也就是说它会在gtk.main()里standby,直到有什么事件发生,然后它就把控制权交到相应的功能模块手里。

这个所谓的“控制权”是怎么回事,它又是怎样传递的呢?这就要通过各个模块之间相系地发信号,这就是所谓的“事件信号”。设想一下,你按了一下鼠标,就这样,被你的鼠标点了一下的那个东西(widget比如一个按钮)就发出了一个相应的“事件信号”。GTK+的精髓也就是这么几句话。有些“事件信号”是各个widget所都有的(比如destroy),而有些是某一种widget特有的(比如toggle button的toggled)。

为了让一个按钮对事件有所反应,我们要给它建立一个事件处理器,这个处理器得知了有事发生之后,就调用了相应的功能模块。这个调用过程是由GtkWidget的一个method完成的:

handler_id = object.connect(name, func, func_data)

object是GtkWidget的一个实例,它会发出“事件信号”,第一个参数name是你想得知并反应的事件的名称。第二个参数func是对事件进行处理的函数,在这个事件发生时调用。第三个参数func_data是要传入func的数据。上面的语句返回一个handle_id,我们根据它对事件处理器进行一些操作,比如中断、挂起。

func就“回调函数”,它一般以这样的形式出现:

def callback_func(widget, callback_data):

widget是指向发出“事件信号”的那个家伙的指针,callback_data是指向传入“回调函数”的数据的指针(就是前面的func_data)。

如果“回调函数”是某一个类的method,则会是这样的形式:

def callback_meth(self, widget, callback_data):

self是执行这个method的对象实例,这和helloworld.py中用法是一样的。

Note
上面所说的只是“回调函数”的一般情况,有一些widget的特殊“事件信号”的处理需要特殊的参数。

在helloworld.py中的另外一种调用方式是:

handler_id = object.connect_object(name, func, slot_object)

connect_object()和connect()的区别在于callback function只用一个参数,而callback method要用两个参数:

object通常是一个widget。connect_object一般使用一个参数的callback_func作为事件处理函数。

1.2.3. Events

1.2.4. Stepping Through Hello World