跳转到内容

PyGTK GUI 编程/信号

来自维基教科书,自由的教科书

正如你在上一章中学到的,信号由小部件发出,以允许你的应用程序响应特定的操作,例如按钮按下。这些响应是通过编写以下形式的函数来创建的

def callback_func(widget, callback_data=None)

并使用小部件的 connect 方法将其注册到特定的小部件和信号

widget.connect(signal_name, callback_function, callback_data)

其中 signal_name 是一个字符串,指示要响应的信号的名称,callback_function 是对你的回调函数的引用(不带括号和参数),callback_data 是一个可选的任意对象,传递给你的回调函数。

如果你在 Python 类中构建你的应用程序,如上一章所示,那么你的回调“方法”将需要一个额外的参数作为对类实例的引用

class App:
    ... snip ...
    def callback_method(self, widget, callback_data):
       ... snip ...

出于组织目的,通常建议将所有回调方法分组在类的末尾,或以 _callback 为后缀。

GTK+ 事件类似于 信号:它们由特定的小部件“发出”,并且可以通过回调函数处理。就 PyGTK 程序员而言,唯一的区别是回调函数的参数及其返回值。举个例子,我们将使用 gtk.Button 小部件发出的“button_pressed_event”,它可以像连接信号一样连接到回调函数

button.connect('button_press_event', callback_func, callback_data)

其中 buttongtk.Button 对象的一个实例。callback_data 参数,如上一章所述,是可选的。回调函数的定义包含三个参数:发出信号的小部件的引用、事件和回调数据

def callback_func(widget, event, callback_data=None)

此函数返回的值 必须 是一个布尔值(与信号的回调函数不同)。此返回值是 GTK+ 事件机制中的重要信息

  • False 表示事件未完全处理,因此 GTK+ 应该继续执行发生此事件时通常执行的操作,并且信号应该进一步传播。
  • True 表示事件完全处理,GTK+ 不再需要对事件进行任何进一步的处理。

例如,“delete_event”事件是从 gtk.Window 发出的,当用户尝试关闭窗口时;如果我们将回调函数连接到此,并且函数返回 False,GTK+ 将继续关闭窗口并发出“destroy”信号。但是,如果我们的回调函数返回 True,GTK+ 会自行关闭窗口或发出“destroy”信号。这使我们能够在有人尝试关闭窗口时进行干预,因此我们有机会询问他们是否要保存他们的工作,然后通过从我们的回调函数返回适当的值来指示 GTK+ 关闭窗口或保持打开状态。

GTK+ 主循环

[编辑 | 编辑源代码]

GTK+ 工具包被称为“事件驱动”,因为它在一个循环中休眠,直到发出信号或事件,此时它将信号添加到 队列 的末尾。GTK+ 的另一个部分从队列的顶部逐个获取信号,并运行与信号或事件注册的任何回调函数,然后再移动到队列中的下一项。这就是你需要运行 gtk.main() 函数的原因,它用于防止你的应用程序在设置完 GUI 后立即停止,并在发出信号和事件时运行你使用 .connect() 注册的任何回调函数。

但是,需要注意的是,GTK+ 不会在新线程中运行回调函数;如果一个回调函数需要很长时间才能运行,那么 GUI 的其余部分将保持无响应,直到该函数完成。以下是一个快速示例来演示这一点

#!/usr/bin/env python

import pygtk
pygtk.require('2.0')
import gtk
import time

class App:
    def __init__(self):
        self.window = gtk.Window(type=gtk.WINDOW_TOPLEVEL)
        self.hbox = gtk.HBox()
        self.button_print = gtk.Button(label='Print something')
        self.button_sleep = gtk.Button(label='Hang for 5 seconds')

        self.hbox.pack_start(self.button_print)
        self.hbox.pack_start(self.button_sleep)

        self.button_print.connect('clicked', self.print_hi)
        self.button_sleep.connect('clicked', self.sleep)
        self.window.connect('destroy', self.quit)
        
        self.window.add(self.hbox)
        self.window.show_all()

        gtk.main()

    def print_hi(self, widget, callback_data=None):
        print 'Hi there!'

    def sleep(self, widget, callback_data=None):
        time.sleep(5)

    def quit(self, widget, callback_data=None):
        gtk.main_quit()

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

如果你从终端运行上面的程序,你应该看到一个有两个按钮的窗口。按下第一个按钮会导致“Hi there!”在终端上打印出来。如果你按下第二个按钮,回调函数会挂起五秒钟,这意味着通过快速连续按下第二个按钮和第一个按钮,“Hi there!”消息将在 5 秒后才会打印出来,这表明信号是如何添加到队列中,并且这些信号是逐个执行的。

PyGTK GUI 编程
 ← 第一步 信号 输入小部件 → 
华夏公益教科书