跳轉到內容

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 程式設計
 ← 第一步 訊號 輸入小部件 → 
華夏公益教科書