1. 程式人生 > >tkinter bind方法支援引數傳遞

tkinter bind方法支援引數傳遞

接上一篇博文(Listbox 與 Scrollbar 聯動設定),接下來該說說事件的事情了。
還是先上程式碼:

from tkinter import *
from tkinter import messagebox

class Win_Program:
    def __init__(self):
        self.master = Tk()
        self.master.state("zoomed") # 視窗最大化
        self.master.title("demo")
        self.master.grid()
        self.databases = list()
        self.var = StringVar()
        for
i in range(40): self.databases.append("database"+str(i)) def get_db_configure(self): top = Toplevel(self.master) top.title("資料庫配置") top.resizable(0,0) # 大小不可變 # 建立的Toplevel物件 在最上層 top.attributes("-toolwindow", 1) top.wm_attributes("-topmost"
, 1) top.grid() sb = Scrollbar(top) sb.grid(row=0, rowspan=20, sticky=E+NS, padx=10, pady=5, column=1) lb = Listbox(top, listvariable=self.var, width=65, yscrollcommand=sb.set, selectmode=SINGLE, height=20) lb.bind(sequence='<Double-Button-1>', func=self.handler_adaptor(self.handler, lb=lb, top=top)) for
i in range(len(self.databases)): lb.insert(0, self.databases[i]) lb.grid(row=0, rowspan=20, column=0, padx=5, pady=5) # Listbox 滾動時,通過lb.yview方法 通知到 Scrollbar 元件 sb.config(command=lb.yview) return top def widget_to_center(self, master, width, height): # 獲取螢幕長/寬 self.width = self.master.winfo_screenwidth() self.height = self.master.winfo_screenheight() x = self.width / 2 - width / 2 y = self.height / 2 - height / 2 master.geometry('%dx%d+%d+%d' % (width, height, x, y)) master.grid() print(self.width, self.height, x, y) def handler(self, event, top, lb): """事件處理函式""" content = lb.get(lb.curselection()) return messagebox.showinfo(title="Hey, you got me!", message="I am {0}".format(content), parent=top) def handler_adaptor(self, fun, **kwds): """事件處理函式的介面卡,相當於中介,那個event是從那裡來的呢,我也納悶,這也許就是python的偉大之處吧""" return lambda event, fun=fun, kwds=kwds: fun(event, **kwds) if __name__ == "__main__": win_program = Win_Program() win_program.widget_to_center(win_program.get_db_configure(), 500, 400) mainloop()

在上一篇文章中,我們能展示所有資料庫配置了。接下來需要一個事件繫結,來完成選擇配置的過程。繫結事件用bind方法,事件繫結有很多,一般通過滑鼠/鍵盤能實現的操作,都可以繫結,比如:單擊,雙擊,組合鍵ctrl+c,組合鍵 ctrl_v等。在我們這個案例中,雙擊選中是一個實用的操作。故:

lb.bind(sequence='<Double-Button-1>', func=self.handler_adaptor(self.handler, lb=lb, top=top))

需要注意的是,bind方法sequence入參是描述滑鼠、鍵盤的操作事件,func入參可傳入一個呼叫函式,但傳遞的函式必須是一個帶event引數的方法,而且只能有這麼一個引數。舉個例子:
定義如下函式:

    def no_other_argues(self, event):
        print("You got me!")

bind方法func入參可換成這樣:

lb.bind(sequence='<Double-Button-1>', func=self.no_other_argues)

雙擊,可以在執行程式碼視窗看到輸出。

重點來了

但很多時候,不支援傳遞引數的bind方法,並不能滿足我們的需求。若需要bind方法的func入參支援多引數,該如何解決呢?這個只能曲線救國了,需要定義一個函式中介:

    def handler_adaptor(self, fun,  **kwds):
        """事件處理函式的介面卡,相當於中介,那個event是從那裡來的呢,我也納悶,這也許就是python的偉大之處吧"""
        return lambda event, fun=fun, kwds=kwds: fun(event, **kwds)

然後再定義自己真正要執行的函式:

    def handler(self, event, top, lb):
        """事件處理函式"""
        content = lb.get(lb.curselection())
        return messagebox.showinfo(title="Hey, you got me!", message="I am {0}".format(content), parent=top)

如此,bind方法就能支援引數傳遞了。

最終效果如下:
20180628