Python之tkinter 事件和綁定

事件綁定的基本簡介

  其實GUI程序是一種事件導向的應用程序設計,事件的來源可能是用戶單擊鼠標、鍵盤輸入或是Widget 狀態改變。tkinter提供一些機制讓我們可以針對這些事件做更進一步的處理,這些處理的方式稱爲事件處理程序

Widget 的 command 參數

例子:複習

import tkinter

def show():
    label.config(text="Click")

def oneVar():
    if varOne.get():
        label.config(text="One!!!")
    else:
        label.config(text="One")

def twoVar():
    if varTwo.get():
        label.config(text="Two!!!")
    else:
        label.config(text="Two")

root = tkinter.Tk()
root.geometry("300x200")

btu = tkinter.Button(root, text="Click", command=show)
btu.pack(anchor=tkinter.W)

varOne = tkinter.BooleanVar()
cbnOne = tkinter.Checkbutton(root, text="One", variable=varOne, command=oneVar)
cbnOne.pack(anchor=tkinter.W)

varTwo = tkinter.BooleanVar()
cbnTwo = tkinter.Checkbutton(root, text="Two", variable=varTwo, command=twoVar)
cbnTwo.pack(anchor=tkinter.W)


label = tkinter.Label(root, bg="lightgreen", fg="red", height=2, width=12, font="Times 16 bold")
label.pack()

root.mainloop()

運行結果:
在這裏插入圖片描述
我們通過command=show,來設計show函數,這個show函數就是事件處理程序

事件綁定

語法格式如下

widget.bind(event, handler)

參數:

  • widget:事件的來源,可以是root窗口對象,或是任意的Widget控件,例如,功能按鈕,選項按鈕,複選框等等
  • 第一個參數:evevt,事件的參數,下面具體說明
  • 第二個參數:handler,事件處理程序,也就是根據event來觸發的函數

下面我們來看具體參數

鼠標相關的事件參數
鼠標事件 說明
<Button-1> 鼠標左鍵單擊
<Button-2> 鼠標中鍵單擊
<Button-3> 鼠標右鍵單擊
<Button-4> 鼠標滑輪向上滾動(Linux)
<Button-5> 鼠標滑輪向下滾動(Linux)
<B1-Motion> 鼠標左鍵拖動
<B2-Motion> 鼠標中鍵拖動
<B3-Motion> 鼠標右鍵拖動
<ButtonRelease-1> 鼠標左鍵釋放
<ButtonRelease-2> 鼠標中鍵釋放
<ButtonRelease-3> 鼠標右鍵釋放
<Double-Button-1> 鼠標左鍵雙擊
<Double-Button-2> 鼠標中鍵雙擊
<Double-Button-3> 鼠標右鍵雙擊
<Enter> 鼠標指針進入控件
<Leave> 鼠標指針離開控件

  上述的參數,執行後鼠標光標相對控件的位置會被存入事件對象的x和y變量中,所以這就是爲什麼我們在handler函數中要加入event形參,這個是必須要傳的

注:

<1> = <Button-1> =<ButtonPress-1>
<2> = <Button-2> = <ButtonPress-2>
<3> = <Button-3> =<ButtonPress-3>

這是通用的,<>不能省略

綁定的方式

button.bind("<Button-1>", handler)
鼠標綁定的基本應用

例子:鼠標移動,右下方看到鼠標目前的座標

import tkinter

def moving(event):
    # .x_root, .y_root是相對於整個屏幕
    # 獲取x軸座標(相對於窗口)
    x = event.x
    # 獲取y軸座標(相對於窗口)
    y = event.y
    textvar = "座標 : x:%r  y:%r" % (x, y)
    var.set(textvar)

root = tkinter.Tk()
root.geometry("300x200")
x, y = 0, 0
var = tkinter.StringVar()
text = "座標 : x:%r  y:%r" % (x, y)
var.set(text)

label = tkinter.Label(root, textvariable=var)
label.pack(anchor=tkinter.S, side=tkinter.RIGHT, padx=10, pady=10)

# 事件是鼠標移動,執行moving函數
root.bind("<Motion>", moving)

root.mainloop()

運行結果:

在這裏插入圖片描述
moving(event)中的event是可以自定義的,但是不能沒有

鍵盤相關的事件參數
鍵盤事件 說明
<Return> 回車
<Cancel> Break鍵
<BackSpace> BackSpace鍵
<Tab> Tab鍵
<Shift_L> 左Shift鍵
<Alt_L> 左Alt鍵
<Control_L> 左Control鍵
<Shift_R> 右Shift鍵
<Alt_R> 右Alt鍵
<Control_R> 右Control鍵
<Pause> Pause鍵
<Caps_Lock> Caps_Lock鍵
<Escape> Escapel鍵,俗稱Esc
<Prior> PageUp鍵
<Next> PageDown鍵
<End> End鍵
<Home> Home鍵
<Left> 左箭頭
<Up> 上箭頭
<Right> 右箭頭
<Down> 下箭頭
<Print> Print Screen
<Insert> Insert鍵
<Delete> Delete鍵
<F1> F1鍵
<F2> F2鍵
<F3> F3鍵
<F4> F4鍵
<F5> F5鍵
<F6> F6鍵
<F7> F7鍵
<F8> F8鍵
<F9> F9鍵
<F10> F10鍵
<F11> F11鍵
<F12> F12鍵
<Num_Lock> Num_Lock鍵
<Scroll_Lock> Scroll_Lock鍵
<plus> 小鍵盤上的 + 鍵
<minus> 小鍵盤上的 - 鍵
<asterisk> 小鍵盤上的 * 鍵
<slash> 小鍵盤上的 / 鍵
<key> 任意鍵

注:

<key> = <KeyPress> = <KeyRelease>
鍵盤綁定的基本應用

例子:當我們按下Tab時,tkinter做出響應

import tkinter

def tab(event):
	# keysym 鍵盤事件對應的字符串
    print(f"按下了{event.keysym}鍵")

root = tkinter.Tk()
root.geometry("100x80")
root.bind("<Tab>", tab)

root.mainloop()

運行結果:
在這裏插入圖片描述

可打印的字符
字符 說明
<a> 字母a
<b> 字母b
此處省略剩下的24個字母 此處省略剩下的24個字母
<1> 數字1
<2> 數字2
此處省略剩下的8個數字 此處省略剩下的8個數字
<A> 按鍵shift+a或者字母大寫A
<B> 按鍵shift+b或者字母大寫B
此處省略剩下的24個大寫字母 此處省略剩下的24個寫字母

注:

<a> = <Key-a> = <KeyPress-a> = <KeyRelease-a>
打印字符的基本應用

例子:當我們按下a時,tkinter做出響應

import tkinter

def tab(event):
    print(f"按下了{event.keysym}鍵")

root = tkinter.Tk()
root.geometry("100x80")
root.bind("<a>", tab)

root.mainloop()

運行結果:
在這裏插入圖片描述

組合鍵
組合鍵 說明
<Shift-Home> Shift+Home
<Alt-Home> Alt+Home
<Control-Home> Ctrl+Home
<Control-A> Ctrl+shift+a

注:

組合鍵不止這些,可以自由組合

組合鍵的基本應用

例子:當我們按下Alt+Home時,tkinter做出響應

import tkinter

def tab(event):
    print(f"按下了home鍵")

root = tkinter.Tk()
root.geometry("100x80")
root.bind("<Alt-Home>", tab)

root.mainloop()

運行結果:
在這裏插入圖片描述

窗體事件
窗體事件 說明
<Configure> 改變大小或位置
<Visibility> 當組件變爲可視狀態時觸發
<Unmap> 當組件由顯示狀態變爲隱藏狀態時觸發
<Map> 當組件由隱藏狀態變爲顯示狀態時觸發
<Expose> 當組件從原本被其他組件遮蓋的狀態中暴漏出來時觸發
<FocusIn> 組件獲得焦點時觸發
<FocusOut> 組件失去焦點時觸發
<Circulate> 當窗體由於系統協議要求在堆棧中置頂或壓底時觸發
<Colormap> 當窗體的顏色或外貌改變時觸發,Tk中忽略此細則
<Property> 當窗體的屬性被刪除或改變時觸發,屬於TK的核心
<Destroy> 當組件被銷燬時觸發
<Activate> 與組件選項中的state項有關,表示組件由不可用變爲可用時觸發
<Deactiavte> 與組件選項中的state項有關,表示組件由可用變爲不可用時候觸發
窗體事件綁定的基本應用

例子:獲得焦點與失去焦點,由Tab鍵進行切換

import tkinter

def a(event):
    label.config(text="獲取焦點")

def b(event):
    label.config(text="失去焦點")

root = tkinter.Tk()
root.geometry("300x200")

btu = tkinter.Button(root, text="Click")
btu.pack(anchor=tkinter.W)
btu.bind("<FocusIn>", a)
btu.bind("<FocusOut>", b)

btu1 = tkinter.Button(root, text="Other")
btu1.pack(anchor=tkinter.W)


label = tkinter.Label(root, bg="lightgreen", fg="red", height=2, width=12, font="Times 16 bold")
label.pack()

root.mainloop()

運行結果:
在這裏插入圖片描述
例子:組件由隱藏狀態變爲顯示狀態,顯示狀態變爲隱藏狀態

from tkinter import *

def show(event):
    b2.config(bg="lightyellow")
    # SystemButtonFace 默認的顏色,就是那個灰色
    b1.config(bg="SystemButtonFace")

def Unshow(event):
    b1.config(bg="lightblue")
    b2.config(bg="SystemButtonFace")

root = Tk()

l1 = Label(root, text='pack_forget')
b3 = Button(root, text='按鈕')
b3.bind("<Unmap>", Unshow)
b3.bind("<Map>", show)

# pack_forget 不顯示
b1 = Button(root, text='隱藏', command=b3.pack_forget)
b2 = Button(root, text='顯示', command=b3.pack)

l1.pack(fill=X)
b1.pack(fill=X)
b2.pack(fill=X)
b3.pack()

root.mainloop()

運行結果:
在這裏插入圖片描述

Event
Event 說明
widget 事件被觸發的控件
.x, .y 鼠標距離窗體左上角的位置(座標)
.x_root, .y_root 鼠標距離屏幕左上角的位置(座標)
.char 鍵盤事件對應的字符代碼
.keysym 鍵盤事件對應的字符串
.keycode 鍵盤事件對應的按鍵碼
.num 鼠標事件對應的按鍵碼
.width, .height 控件的新大小
.type 事件類型
Event的基本應用

例子:鍵盤輸入,tkinter響應字符串和按鍵碼(ASCII)

import tkinter

def show(event):
    print(f"{event.keysym}對應的ASCII碼:{event.keycode}")

win = tkinter.Tk()
win.geometry("150x100")
win.bind("<Key>", show)

win.mainloop()

運行結果:
在這裏插入圖片描述

對於ASCII的說明

  每套鍵盤可能對應的ASCII都不同,所以在這裏我並沒有寫明每個字母、字符、數字的ASCII值,即使寫了可能也與大家的ASCII值不同,怎樣得知自己鍵盤的ASCII值呢?

  上述的方法獲取是最好驗證的,請參照Event的基本應用中的例子

取消綁定

取消綁定xx的方法如下:

# <xxx>是綁定方式
xx.unbind("<xxx>")

例子

import tkinter

def show(event):
    label.config(text="ForPython!")

def choose(x):
    if var.get():
        x.bind("<Button-1>", show)
    else:
        label.config(text="")
        x.unbind("<Button-1>")

root = tkinter.Tk()
root.geometry("300x200")

btu = tkinter.Button(root, text="Click")
btu.pack(anchor=tkinter.W)

var = tkinter.BooleanVar()
cbut = tkinter.Checkbutton(root, text="bind/unbind", variable=var, command=lambda: choose(btu))
cbut.pack(anchor=tkinter.W)


label = tkinter.Label(root, bg="lightgreen", fg="red", height=2, width=12, font="Times 16 bold")
label.pack()

root.mainloop()

運行結果:
在這裏插入圖片描述

一個事件綁定多個事件處理程序

  使用bind()方法可以綁定一個事件處理程序,tkinter也允許我們執行一個事件綁定多個事件處理程序,同樣使用bind()方法,但是新增加的時間處理程序需要在bind()方法內增加參數add = "+"

例子

import tkinter


def show():
    print("???")


def shower(event):
    print("!!!")


root = tkinter.Tk()
button = tkinter.Button(root, text="Click", command=show)
button.pack()
button.bind("<1>", shower, add="+")

root.mainloop()

在這裏插入圖片描述

程序會先執行bind()綁定的程序,然後再執行Button()command指定的程序

Protocols

Protocols 可以翻譯爲通信協議,在tkinter內可以解釋爲窗口管理程序(Windows Manager)與應用程序(Application)之間的通信協議。tkinter也支持使用綁定概念更改此通信協議

例子:退出程序詢問是否要退出

import tkinter
from tkinter import messagebox


def show():
    res = messagebox.askokcancel("提示", "請問您確定要退出嗎?")
    if res:
        root.destroy()
    else:
        return


root = tkinter.Tk()
root.protocol("WM_DELETE_WINDOW", show)

root.mainloop()

運行結果:
在這裏插入圖片描述

謝謝觀看,筆者會持續更新,如有錯誤或者建議,請私信我

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