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)
其中 button 是 gtk.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.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 秒後才會打印出來,這表明訊號是如何新增到佇列中,並且這些訊號是逐個執行的。