2020年9月12日星期六

74 《零基礎入門學習Python》筆記 第074講:GUI的終極選擇:Tkinter11

《零基礎入門學習Python》第074講:GUI的終極選擇:Tkinter11


今天我們來講講事件綁定。正如我們此前所提到的,一個tkinter 的應用程序大部分時間是花費在事件循環中的,也就是通過mainloop() 方法進入時間循環了,事件可以有各種各樣的來源,比如說用戶移動、點擊一下鼠標,會產生對應的鼠標事件,在鍵盤上一個敲擊,會產生對應的按鍵事件,拖動或者改變應用程序的大小,窗口管理器也會觸發相應的重繪事件啦。
tkinter 提供一個非常強大的機制可以讓你自由的去管理這些事件,定義這些事件的操作,對每一個組件來說,你可以通過bind() 方法將自己定義的函數或者方法綁定到具體的事件上,我們在此之前已經演示過很多次啦,當被觸發的事件滿足該組件綁定的事件的時候,tkinter 就會帶著事件本身的描述去調用自定義的方法了,我們這裡有幾個例子給大家感受一下。

第一個是關於鼠標按鍵的演示:

我們創建一個框架frame ,然後在這個框架裡響應事件就可以了,寬度、高度均為200,<Button-1>,中間有一個小橫槓,左邊是事件本身,右邊是事件的描述,Button 表示鼠標的點擊事件,1 表示鼠標左鍵(2:中間鍵;3:右鍵;4和5是對於Linix 系統才有用,對應滾輪的上滾和下滾),我們對這個事件綁定一個自定義的方法:callback(),我們說,當觸發Button-1 這個事件(即點擊鼠標左鍵)的時候,tkinter 會帶著事件本身去調用callback() 方法,它就把這個事件傳到這個方法的參數裡面,我們這裡就需要一個形參來獲取,這裡命名為event,用其他名字也一樣,event 形參來獲取對應的事件描述,我們就簡單的把點擊那一刻鼠標的位置打印出來,event.x和event.y,這裡的x,y 表示的是相對於應用程序左上角的相對位置,還有一個root.x 和root.y,是相對於屏幕的位置。我們下面介紹。
  1. # 捕获点击鼠标的位置
  2. import tkinter as tk
  3. root = tk.Tk()
  4. def callback(event):
  5. print("点击位置:", event.x, event.y)
  6. frame = tk.Frame(root, width = 200, height = 200)
  7. frame.bind("<Button-1>", callback)
  8. frame.pack()
  9. root.mainloop()
運行結果也表明了:越接近左上角越接近於0。

第二個是關於鍵盤按鍵的演示:

鍵盤相應的是Key,也可以是KeyPress(鍵盤按下),其實,有按下就有釋放的過程,像剛才的Button,也有ButtonRelease,這裡總之響應一個Key 就可以了,關於鍵盤的事件,有一個特別的要求,就是說,你這個組件想要響應鍵盤事件,因為一個窗口可能會有很多組件,鍵盤一次敲擊,也不知道給哪個組件,所以他有一個要求,就是你這個組件必須獲得焦點,它才會響應鍵盤來的消息,那怎麼獲取焦點呢?我們可以設置Frame 的takefocus 選項為True,然後運行時使用Tab 將焦點轉移上來。這裡有一個更便捷的方法:用focus_set() 獲得焦點。鍵盤有一個char 屬性,就是你剛才按下的字符。
  1. # 捕获键盘事件
  2. import tkinter as tk
  3. root = tk.Tk()
  4. def callback(event):
  5. print("点击的键盘字符为:", event.char)
  6. frame = tk.Frame(root, width = 200, height = 200)
  7. frame.bind("<Key>", callback)
  8. frame.focus_set()
  9. frame.pack()
  10. root.mainloop()
但是上面的例子中,當我們點擊ALT、Ctrl、Shift這一類特殊按鍵時,就不會顯示,但是可以通過把event.char改為event.keysym或者event.keycode來得到對應按鍵的keysym和keycode (參照下面的Key names小節

最後我們再用一個例子展示捕獲鼠標在組件上的運動軌跡,這裡需要關注的是<Motion> 事件:

  1. # 捕获鼠标在组件上的运动轨迹
  2. import tkinter as tk
  3. root = tk.Tk()
  4. def callback(event):
  5. print("当前位置为:", event.x, event.y)
  6. frame = tk.Frame(root, width = 200, height = 200)
  7. frame.bind("<Motion>", callback)
  8. frame.pack()
  9. root.mainloop()
截止目前為止,我們都是泛泛的跟大家說怎麼用,現在我們主要談一下語法性的東西啦,首先,我們剛才的Button、Key、KeyPress、Motion 都稱之為時間序列。
Tkinter 使用一種稱為事件序列的機制來允許用戶定義事件,用戶需使用bind() 方法將具體的事件序列與自定義的方法相綁定。事件序列是以字符串的形式表示的,可以表示一個或多個相關聯的事件(如果是多個事件,那麼對應的方法只有在滿足所有事件的前提下才會被調用)。

事件序列使用以下語法描述:
<modifier-type-detail>
  • 事件序列是包含在尖括號(<...>)中
  • type 部分的內容是最重要的,它通常用於描述普通的事件類型,例如鼠標點擊或鍵盤按鍵點擊(詳見下方)。
  • modifier 部分的內容是可選的,它通常用於描述組合鍵,例如Ctrl + c,Shift + 鼠標左鍵點擊(詳見下方)。
  • detail 部分的內容是可選的,它通常用於描述具體的按鍵,例如Button-1 表示鼠標左鍵。
舉幾個例子幫助大家消化:
事件序列含義
<Button-1>用戶點擊鼠標左鍵
<KeyPress-H>用戶點擊H 按鍵
<Control-Shift-KeyPress-H>用戶同時點擊Ctrl + Shift + H
type
type含義
Activate當組件的狀態從“未激活”變為“激活”的時候觸發該事件
Button1.當用戶點擊鼠標按鍵的時候觸發該事件
2. detail部分指定具體哪個按鍵:<Button-1>鼠標左鍵,<Button-2>鼠標中鍵,<Button-3>鼠標右鍵,<Button- 4>滾輪上滾(Linux),<Button-5>滾輪下滾(Linux)
ButtonRelease1.當用戶釋放鼠標按鍵的時候觸發該事
2.在大多數情況下,比Button要更好用,因為如果當用戶不小心按下鼠標,用戶可以將鼠標移出組件再釋放鼠標,從而避免不小心觸發事件
Configure當組件的尺寸發生改變的時候觸發該事件
Deactivate當組件的狀態從“激活”變為“未激活”的時候觸發該事件
Destroy當組件被銷毀的時候觸發該事件
Enter1.當鼠標指針進入組件的時候觸發該事件
2.注意:不是指用戶按下回車鍵
Expose當窗口或組件的某部分不再被覆蓋的時候觸發該事件
FocusIn1.當組件獲得焦點的時候觸發該事件
2.用戶可以用Tab鍵將焦點轉移到該組件上(需要該組件的takefocus選項為True)
3.你也可以調用focus_set()方法使該組件獲得焦點(見上方例子)
FocusOut當組件失去焦點的時候觸發該事件
KeyPress1.當用戶按下鍵盤按鍵的時候觸發該事件
2. detail可以指定具體的按鍵,例如<KeyPress-H>表示當大寫字母H被按下的時候觸發該事件
3. KeyPress可以簡寫為Key
KeyRelease當用戶釋放鍵盤按鍵的時候觸發該事件
Leave當鼠標指針離開組件的時候觸發該事件
Map1.當組件被映射的時候觸發該事件
2.意思是在應用程序中顯示該組件的時候,例如調用grid()方法
Motion當鼠標在組件內移動的整個過程均觸發該事件
MouseWheel1.當鼠標滾輪滾動的時候觸發該事件
2.目前該事件僅支持Windows和Mac系統,Linux系統請參考Button
Unmap1.當組件被取消映射的時候觸發該事件
2.意思是在應用程序中不再顯示該組件的時候,例如調用grid_remove()方法
Visibility當應用程序至少有一部分在屏幕中是可見的時候觸發該事件
modifier
在事件序列中,modifier 部分的內容可以是以下這些:
modifier含義
Alt當按下Alt 按鍵的時候
Any1.表示任何類型的按鍵被按下的時候
2.例如<Any-KeyPress>表示當用戶按下任何按鍵時觸發事件
Control當按下Ctrl 按鍵的時候
Double1.當後續兩個事件被連續觸發的時候
2.例如<Double-Button-1>表示當用戶雙擊鼠標左鍵時觸發事件
Lock當打開大寫字母鎖定鍵(CapsLock)的時候
Shift當按下Shift 按鍵的時候
Triple跟Double 類似,當後續三個事件被連續觸發的時候
Event 對象
當Tkinter 去回調你定義的函數的時候,都會帶著Event 對象(作為參數)去調用,Event 對像以下這些屬性你可以使用:
屬性含義
widget產生該事件的組件
x, y當前的鼠標位置坐標(相對於窗口左上角,像素為單位)
x_root, y_root當前的鼠標位置坐標(相對於屏幕左上角,像素為單位)
char按鍵對應的字符(鍵盤事件專屬)
keysym按鍵名,見下方Key names(鍵盤事件專屬)
keycode按鍵碼,見下方Key names(鍵盤事件專屬)
num按鈕數字(鼠標事件專屬)
width, height組件的新尺寸(Configure 事件專屬)
type該事件類型
Key names
當事件為<Key>,<KeyPress>,<KeyRelease> 的時候,detail 可以通過設定具體的按鍵名(keysym)來篩選。例如<Key-H> 表示按下鍵盤上的大寫字母H 時候觸發事件,<Key-Tab> 表示按下鍵盤上的Tab 按鍵的時候觸發事件。
下表列舉了鍵盤所有特殊按鍵的keysym和keycode:
(下邊按鍵碼是對應美國標準101鍵盤的“Latin-1”字符集,鍵盤標準不同對應的按鍵碼不同,但按鍵名是一樣的)
按鍵名(keysym)按鍵碼(keycode)代表的按鍵
Alt_L64左邊的Alt 按鍵
Alt_R113右邊的Alt 按鍵
BackSpace22Backspace(退格)按鍵
Cancel110break 按鍵
Caps_Lock66CapsLock(大寫字母鎖定)按鍵
Control_L37左邊的Ctrl 按鍵
Control_R109右邊的Ctrl 按鍵
Delete107Delete 按鍵
Down104↓ 按鍵
End103End 按鍵
Escape9Esc 按鍵
Execute111SysReq 按鍵
F167F1 按鍵
F268F2 按鍵
F369F3 按鍵
F470F4 按鍵
F571F5 按鍵
F672F6 按鍵
F773F7 按鍵
F874F8 按鍵
F975F9 按鍵
F1076F10 按鍵
F1177F11 按鍵
F1296F12 按鍵
Home97Home 按鍵
Insert106Insert 按鍵
Left100← 按鍵
Linefeed54Linefeed(Ctrl + J)
KP_090小鍵盤數字 0
KP_187小鍵盤數字 1
KP_288小鍵盤數字 2
KP_389小鍵盤數字 3
KP_483小鍵盤數字 4
KP_584小鍵盤數字 5
KP_685小鍵盤數字 6
KP_779小鍵盤數字 7
KP_880小鍵盤數字 8
KP_981小鍵盤數字 9
KP_Add86小鍵盤的+ 按鍵
KP_Begin84小鍵盤的中間按鍵(5)
KP_Decimal91小鍵盤的點按鍵(.)
KP_Delete91小鍵盤的刪除鍵
KP_Divide112小鍵盤的/ 按鍵
KP_Down88小鍵盤的↓ 按鍵
KP_End87小鍵盤的End 按鍵
KP_Enter108小鍵盤的Enter 按鍵
KP_Home79小鍵盤的Home 按鍵
KP_Insert90小鍵盤的Insert 按鍵
KP_Left83小鍵盤的← 按鍵
KP_Multiply63小鍵盤的* 按鍵
KP_Next89小鍵盤的PageDown 按鍵
KP_Prior81小鍵盤的PageUp 按鍵
KP_Right85小鍵盤的→ 按鍵
KP_Subtract82小鍵盤的- 按鍵
KP_Up80小鍵盤的↑ 按鍵
Next105PageDown 按鍵
Num_Lock77NumLock(數字鎖定)按鍵
Pause110Pause(暫停)按鍵
Print111PrintScrn(打印屏幕)按鍵
Prior99PageUp 按鍵
Return36Enter(回車)按鍵
Right102→ 按鍵
Scroll_Lock78ScrollLock 按鍵
Shift_L50左邊的Shift 按鍵
Shift_R62右邊的Shift 按鍵
Tab23Tab(製表)按鍵
Up98↑ 按鍵


0 留言:

發佈留言