跳转到内容

PyGTK GUI 编程/入门

来自维基教科书,开放的书籍,开放的世界

本章旨在使读者熟悉 PyGTK 模块的基本类和函数,以及如何将它们链接在一起。首先,打开一个交互式 Python shell(例如启动 IDLE,或在终端的命令行中键入`python`),并输入以下内容(区分大小写)

import gtk

window = gtk.Window()
label = gtk.Label("Hello, world!")

window.add(label)

window.show_all()

如果您将上面的代码输入到一个文件中并执行该文件(通过使用文件作为参数调用解释器,或者通过其他一些 IDE 间接调用),那么可能会发生什么都没有发生。这是因为在 `window.show_all()` 调用之后,解释器(以及 PyGTK 应用程序)正在终止。为了使这个例子在这种情况下工作,只需在最后追加 `gtk.main()` 即可,更多细节请参见“信号和回调”部分。

PyGTK 的一些版本中存在一个错误,会导致 IDLE 在使用 `gtk` 模块时崩溃。如果您启动 IDLE,开始输入上面的行,并且突然 IDLE 窗口关闭或消失 - 通常发生在您在一行末尾按 [Enter] 时 - 那么您就遇到了这个错误!打开一个命令 shell/终端,键入“python”命令,按 [Enter],然后再次启动上面的脚本。
技术说明


这段代码创建了一个窗口,其中包含“Hello, world!”文本(见截图)。

  • 第 1 行:这将导入 gtk 库,以便我们访问构建 GUI 所需的类和函数。
  • 第 3 行:创建一个新的 `Window` 对象,并将其分配给变量 `window`。请注意,默认情况下,这不会立即在屏幕上显示窗口 - 通常的做法是在所有部件都添加到窗口后才进行。
  • 第 4 行:创建一个新的 `gtk.Label` 部件。第一个参数是要在标签中显示的字符串。
  • 第 6 行:`Window` 的 `add()` 方法是将部件附加到它的其中一种方法。
  • 第 8 行:`Window` 类的 `show_all()` 方法调用其所有子部件(已放置在窗口内部的部件)上的 `show()` 方法,然后调用包含窗口本身的 `show()` 方法。

GTK 对象和容器

[edit | edit source]

在上面的示例代码中,`gtk.Window()` 对象明显地表示 GUI 窗口,部件 `gtk.Label` 使用 `add()` 方法添加到该对象。但是,`add` 方法只允许将单个对象添加到窗口。由于您通常希望将多个部件放入一个窗口,因此需要添加某种容器对象,例如 `gtk.VBox`。`gtk.VBox` 对象可以包含和组织多个部件到一个**垂直**列中。类似地,`gtk.HBox` 对象也可用,它将子部件组织到一个**水平**行中。为了创建更复杂的布局,您可以嵌套容器对象,即在一个 `gtk.VBox` 内部有一个 `gtk.HBox`。

这些对象的用法在右侧的插图中展示。`gtk.WindowGroup` 对象是可选的,但允许您的应用程序显示多个 `gtk.Window`。本章“多个窗口”解释了如何使用它;目前,我们将坚持使用一个窗口。


这是一个简单的 PyGTK 程序的示例,它利用 `gtk.VBox` 和 `gtk.HBox` 对象将多个部件放到屏幕上 - 尝试在交互式 Python 或 IDLE 解释器中键入以下内容

import gtk

window = gtk.Window()
entry = gtk.Entry()
button_ok = gtk.Button("OK")
button_cancel = gtk.Button("Cancel")

vbox = gtk.VBox()
vbox.pack_start(entry)
hbox = gtk.HBox()
hbox.pack_start(button_ok)
hbox.pack_start(button_cancel)
vbox.pack_start(hbox)

window.add(vbox)
window.show_all()

上面的代码的结果应该是带有输入框和两个按钮的窗口。

  • 第 3 行:创建一个新的 `gtk.Window` 对象。
  • 第 4 行:创建一个新的 `gtk.Entry` 对象(输入框)。
  • 第 5 & 6 行:创建两个新的 `gtk.Button` 对象,文本作为第一个参数。
  • 第 8 行:创建一个新的 `gtk.VBox` 对象。稍后将其添加到窗口,并将包含窗口中的所有部件。
  • 第 9 行:容器上的 `.pack_start()` 方法将作为其第一个参数传递的部件添加到容器的开头(在顶部)。与窗口的 `.add()` 方法不同,这允许在多次调用时添加多个部件。`.pack_end()` 方法执行相同操作,但从容器的末尾(底部)开始放置对象,因此后续调用将部件放置在之前的部件之上。
  • 第 10 行:创建另一个容器对象。
  • 第 11 & 12 行:使用 `.pack_start()` 方法将按钮部件添加到这个新的 `hbox` 容器中。
  • 第 13 行:通过在 `vbox` 容器上调用 `.pack_start()` 方法,将 `hbox` 容器嵌套到 `vbox` 容器中。
  • 第 15 行:使用窗口的 `.add()` 方法将 `vbox` 容器添加到窗口。
  • 第 16 行:显示所有对象,因此您现在可以在屏幕上看到窗口。

信号和回调

[edit | edit source]

为了使您的应用程序对 GUI 做出反应,您可以利用发生在部件上的**事件**,并告诉 PyGTK 在该事件发生时运行一个函数(称为**回调函数**)。例如,当用户点击一个按钮时,该特定部件的“clicked”事件被发出,如果您已将其连接到一个回调函数,则该函数就会运行。

要将事件与函数连接,请在将要发出事件的部件上调用 `.connect()` 方法。此方法的语法如下:

handler_id = widget.connect(event_name, callback_function[, function_data])

`.connect()` 的返回值可以被捕获,以便可以撤销连接。

  • `event_name` 参数应该是一个字符串,表示要连接的事件的名称。这在部件之间有所不同;例如,`gtk.Button` 部件在被点击时会发出一个“clicked”事件。
  • `callback_function` 应该是一个对您希望 PyGTK 在发出 `event_name` 时运行的回调函数的引用。不要在名称末尾添加括号 (),也不需要将其括在字符串中。
  • 可选的 `function_data` 参数可以包含传递给回调函数的其他参数。

回调函数应该采用以下形式:

def callback_function(widget, callback_data=None)

函数的名称及其参数可以调用任何内容。

  • 第一个参数 `widget` 是对发出信号的部件对象的引用。
  • 第二个参数 `callback_data` 包含作为部件的 `connect()` 方法的最后一个参数指定的 `callback_data`(如果提供)。

最后,为了确保处理您的事件,请在应用程序的末尾添加以下代码

gtk.main()

`.gtk.main()` 函数监听事件,并运行已连接到它们的任何回调函数。此函数一直运行,直到窗口被操作系统窗口管理器关闭,或者运行 `.gtk.main_quit()`。

下面是上面示例代码的修改版本,其中定义了一些回调函数,并将其连接到按钮事件。

import gtk

# Define the callback functions first:
def exit(widget, callback_data=None):
  window.hide_all()
  gtk.main_quit()

window = gtk.Window()
entry = gtk.Entry()
button_ok = gtk.Button("OK")
button_cancel = gtk.Button("Cancel")

# Connect events to callback functions:
button_cancel.connect("clicked", exit)

vbox = gtk.VBox()
vbox.pack_start(entry)
hbox = gtk.HBox()
hbox.pack_start(button_ok)
hbox.pack_start(button_cancel)
vbox.pack_start(hbox)

window.add(vbox)
window.show_all()
# Put gtk.main() last so our callback functions are used.
gtk.main()
  • 第 4-6 行:这是一个回调函数,它使用 `.hide()` 方法关闭窗口并停止 `gtk.main()` 循环。虽然 `callback_data` 参数没有被使用,但通常在所有回调函数中包含它很有帮助,以防它在某些时候需要。
  • 第 14 行:`.connect()` 方法捕获来自 `button_cancel` 部件的“clicked”事件,并将其发送到我们之前定义的 `exit()` 回调函数。
  • 第 26 行:`.gtk.main()` 函数启动 `主循环`,它将事件/信号发送到正确的回调函数。

整合所有

[edit | edit source]

以下代码使用上面讨论的所有方法来创建一个非常简单的 GTK 应用程序,它会询问您的姓名,并将它打印到控制台中。将以下文本复制并保存到一个文件中,然后在命令行中运行 `python example.py`(用您刚创建的文件的名称替换 `example.py`)。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import pygtk
pygtk.require('2.0')

import gtk


class Application():
    
    def __init__(self):
        self.window = gtk.Window()
        self.window.set_title("Example GTK Application")
        
        self.create_widgets()
        self.connect_signals()
        
        self.window.show_all()
        gtk.main()
    
    
    def create_widgets(self):
        self.vbox = gtk.VBox(spacing=10)
        
        self.hbox_1 = gtk.HBox(spacing=10)
        self.label = gtk.Label("Your Name:")
        self.hbox_1.pack_start(self.label)
        self.entry = gtk.Entry()
        self.hbox_1.pack_start(self.entry)
        
        self.hbox_2 = gtk.HBox(spacing=10)
        self.button_ok = gtk.Button("OK")
        self.hbox_2.pack_start(self.button_ok)
        self.button_exit = gtk.Button("Exit")
        self.hbox_2.pack_start(self.button_exit)
        
        self.vbox.pack_start(self.hbox_1)
        self.vbox.pack_start(self.hbox_2)
        
        self.window.add(self.vbox)
    
    
    def connect_signals(self):
        self.button_ok.connect("clicked", self.callback_ok)
        self.button_exit.connect("clicked", self.callback_exit)
    
    
    def callback_ok(self, widget, callback_data=None):
        name = self.entry.get_text()
        print name
    
    
    def callback_exit(self, widget, callback_data=None):
        gtk.main_quit()
    

if __name__ == "__main__":
    app = Application()

此应用程序的结构在单个类 `Application` 内。这种方法允许 GTK 部件和其他对象的名字驻留在它们自己的命名空间中,并且还可以让程序员在其他脚本中导入该文件,并由程序员决定何时创建和显示 GUI。

  • 第 4 & 5 行:这两行必须放在 `import gtk` 语句之上。它们处理 GTK+ 工具包在创建 GUI 之前需要执行的所有初始化和版本检查。虽然我们在之前的示例中省略了它,但您仍然应该在自己的程序中使用它,以避免潜在的重绘问题。
  • 第 12 行:`__init__()` 方法在类构造时被调用,它执行以下操作来设置应用程序
    • 第 13 & 14 行:创建一个 `gtk.Window` 对象,并使用它的 `.set_title()` 方法告诉 GTK 在窗口标题栏中显示什么字符串。
    • 第 16 行:运行 **create_widgets()** 方法,该方法创建所有容器和窗口部件,并将窗口部件打包到正确的容器中。
    • 第 17 行:运行 **connect_signals()** 方法,该方法将按钮上的“单击”事件连接到几个回调方法。
    • 第 19 和 20 行:递归地显示窗口中的所有窗口部件,然后运行 **gtk.main()** 循环以响应事件。
  • 第 49 行:此回调方法连接到我们“确定”按钮上的“单击”事件,使用 **gtk.Entry** 窗口部件的 **get_text()** 方法获取文本,并将其打印到控制台。请注意,**回调函数** 和 **回调方法**(此处使用)之间的区别在于,回调方法在开头有一个额外的参数 **self**,因为它是在类中定义的,因此 Python 解释器会将该类的属性和方法传递给它。
  • 第 55 行:此回调方法通过停止 **gtk.main()** 循环来退出应用程序。请注意,它不必在窗口对象上运行 **.hide_all()** 方法,因为窗口在应用程序停止运行时会销毁。
使用 PyGTK 进行 GUI 编程
 ← 介绍 第一步 信号 → 
华夏公益教科书