Tkinter 事件和綁定

6.事件和綁定

正如前幾章提到的,Tkinter應用程序大部分事件都在事件循環中(通過mainloop方法進入事件循環)

事件來自於多個來源,比如用戶的鍵盤的輸入和鼠標操作,和window manager的重繪事件(大多數情況下不是有用戶直接調用的)

Tkinter提供強大的機制讓您自己處理事件,每個組件你都可以爲各種事件綁定python的函數和方法

widget.bind(event, handler)

如果組件中發生了與event描述匹配的事件,將調用handler指定的處理程序,

例子,在窗口中捕獲點擊次數

from Tkinter import *

root = Tk()

def callback(event):
    print "clicked at", event.x, event.y

frame = Frame(root, width=100, height=100)
frame.bind("<Button-1>", callback)
frame.pack()

root.mainloop()

在這裏例子中,我們用bind方法把frame的鼠標左鍵點擊事件綁定到callback函數

當控件擁有鍵盤焦點後,鍵盤事件將發送到對應的控件,你可以使用focus_set

方法來獲得鍵盤焦點,獲取鍵盤事件的代碼:

from Tkinter import *

root = Tk()

def key(event):
    print "pressed", repr(event.char)

def callback(event):
    frame.focus_set()
    print "clicked at", event.x, event.y

frame = Frame(root, width=100, height=100)
frame.bind("<Key>", key)
frame.bind("<Button-1>", callback)
frame.pack()

root.mainloop()

事件


事件用格式化的字符串來表示

<modifier-type-detail>

type區域是事件說明符中最重要的部分,它說明我們想綁定哪一類的事件

例如Button\Key或者如進入、配置之類的窗口管理事件。Modifier和detail區域用於額外的信息

在許多情況下可以省略,還有各種方法來簡化事件字符串,例如爲了匹配鍵盤鍵,您可以省略

尖括號,只需使用鍵,當然要包含在尖括號內讓我們來看看最常見的事件格式

事件格式

<Button-1>鼠標左鍵按下事件,1表示左鍵;2-鼠標中鍵;3-鼠標右鍵

當您在組件上按下鼠標左鍵,隨後的鼠標事件(移動、釋放)就會發送到當前組件,即使

鼠標移動到當前組件之外,鼠標指針的的當前位置在傳遞給回調函數的event對象的x,y中

<Button-1>、<ButtonPress-1>、<1>都是同義詞

<B1-Motion>按住鼠標左鍵移動鼠標,鼠標指針的當前位置在傳遞給回調函數的event中的x\y提供

<ButtonRelease-1>鼠標左鍵被釋放

<Double-Button-1>鼠標左鍵被雙擊,你可以用Double表示雙擊,還可以用Triple表示三擊

注意,如果你綁定了<Button-1>和<Double-Button-1>,那麼2個事件都被觸發

<Enter>當鼠標進入組件區域被觸發

<Leave>當鼠標離開組件區域被觸發

<FocusIn>當鍵盤焦點移到這個組件,或者移到這個組件的子組件

<FocusOut>失去焦點

<Return>用戶按下回車鍵,你可以綁定鍵盤上幾乎所有鍵,Shift_L(左邊的shift鍵)

Delete\F1\F5\Num_Lock都可以

<Key>用戶按下任意鍵

<Shift-Up>用戶按下shift鍵同時按下向上鍵觸發,也可以用Alt,shift,control

frame1.bind("<Shift M>",shiftm) 當同時按下shift 和m 後回調函數shiftm

<Configure>如果組件的尺寸變化那麼被觸發

Event對象

event對象是標準的Python對象實例,有許多屬性

事件屬性

widget:產生這個事件的組件,這個一個合法Tkinter組件實例而不是名字,所有的事件都有這個屬性

x,y:當前鼠標的位置,像素爲單位

x_root,y_root:當前鼠標相對於上層框架的位置

char:字符碼 只有鍵盤事件纔有,string類型

keysym:鍵盤符號只有鍵盤事件纔有

keycode:鍵盤代碼

num:鼠標的編號,左鍵1,中鍵2,右鍵3....

width,height:組件新尺寸,只有Configure 事件纔有,像素

type:事件類型

實例和類的綁定

以上的例子中我們用的都是在實例上使用bind方法,這意味着這樣只能bind在一個組件上,

如果我們創建一個新的組件,他們不會繼承這些綁定關係。

不過Tkinter也提供了類級別和應用級別的bind,實際上,你可以使用以下級別的binding

1.組件實例

2.組件的頂層窗體(Toplevel 或者 root)

3.組件類,用bind_class方法

4.整個應用,用bind_all方法

比如,你可以用bind_all來綁定F1按鈕的點擊,這樣你能在這個應用的如何地方點擊都可以彈出幫助框

但如果同一個鍵你在多處綁定了怎麼辦?

首先,在以上4個層次之內,Tkinter選擇最接近匹配的方式。比如爲<Key>

和<Return>事件創建實例綁定,那麼只有按下Enter鍵之後纔會調用<Return>的回調函數

但是,如果你如果在以上4個層次間,比如你同時向toplevel組件添加<Return>綁定,那麼將調用2個綁定

Tkinter首先調用實例級別的最佳綁定,最後在應用程序級別調用最佳可用綁定,因此,

在極端情況下,單個事件可以調用4個事件處理程序。

常見的混亂原因是當您嘗試使用綁定來覆蓋標準組件的默認行爲。例如,假設你想在

文本框內禁止輸入回車鍵,這樣用戶就無法輸入多行數據,也行你會用下面的小伎倆

def ignore(event):

     pass

text.bind("<Return>",ignore)

或者,你喜歡一行的簡潔代碼

text.bind("<Return>",lamdba e:None)

不幸的是,新的一行依然會插入,因爲,以上的綁定僅僅應用在應用級別,

而標準的行爲依然有類級別的綁定實現了。

你可以使用bind_class方法來改變類級別的綁定,但這將更改應用程序中所有文本組件的行爲。下面是比較合理的解決辦法

def ignore(event):
    return "break"
text.bind("<Return>", ignore)

順便說一句,如果你真的想改變所有文本組件的默認行爲,你可以用以下bind_class方法

top.bind_class("Text""<Return>"lambda e: None)

真的不建議這麼做,不要改變組件的默認行爲。

協議

除了事件綁定,Tkinter還提供了協議處理的機制,這裏的協議指的是應用程序和windows manager之間的互動

最常見的是WM_DELETE_WINDOW,用於定義當用戶使用窗口管理器顯式關閉窗口是的事件。

你可以用protocol方法來安裝這個協議的回調函數(這個組件必須是root或者Toplevel組件)

widget.protocol("WM_DELETE_WINDOW", handler)

一旦你註冊了自己的處理函數,Tkinter將不再自動的關閉程序,比如下面這個例子

Capturing destroy events

from Tkinter import *
import tkMessageBox

def callback():
    if tkMessageBox.askokcancel("Quit""Do you really wish to quit?"):
        root.destroy()

root = Tk()
root.protocol("WM_DELETE_WINDOW", callback)

root.mainloop()

注意,即使你沒有在頂層窗口註冊WM_DELETE_WINDOW的處理程序,窗口還是會被銷燬的。最好還是自己註冊一個處理程序

top = Toplevel(...)#確保窗口小部件實例被刪除 
top.protocol(
“WM_DELETE_WINDOW”,top.destroy)


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章