簡體   English   中英

Python tkinter 當頂層 object 被破壞時,與頂層綁定<destroy>綁定命令執行多次</destroy>

[英]Python tkinter When Toplevel object is destroyed, With toplevel binding for <Destroy> the bound command executes multiple times

在下面的代碼中,當頂層window被銷毀時,bind語句中的命令被執行了多次。 可能為頂級中的每個子小部件一次。 當我將頂層更改為框架時,綁定命令只執行一次。 在示例中,quit() 或 raise SystemExit 被推遲到命令完成其循環。 為什么會這樣?

import tkinter as tk
from tkinter import ttk
from tkinter.messagebox import showinfo

class PlainFrame(tk.Frame):
    def __init__(self,parent):
        super().__init__(parent)
        self.butts = []
        for i in range(20) :
            # button
            self.butts.append(ttk.Button(self, text=f'Click Me {i}'))
            self.butts[i]['command'] = self.button_clicked
            self.butts[i].grid(column=0,row=i)
        self.pack()

    def button_clicked(self):
        showinfo(title='Information',
                 message='Hello, Tkinter!')

class MainFrame(tk.Toplevel):
#class MainFrame(tk.Frame):
    def __init__(self, container,*args,**kwargs):
        super().__init__(container,kwargs)

        options = {'padx': 5, 'pady': 5}

        # label
        self.label = ttk.Label(self, text='Hello, Tkinter!')
        self.label.pack(**options)
        self.quit_button = ttk.Button(self,text='Quit',
                                      command = self._quit)
        self.quit_button.pack()
        self.frame = PlainFrame(self)
        # add when frame
        #self.pack()

    def button_clicked(self):
        showinfo(title='Information',
                 message='Hello, Tkinter!')

    def _quit(self):
        self.destroy()
    

class App(tk.Tk):
    def __init__(self):
        super().__init__()
        # configure the root window
        self.title('My Awesome App')
        self.geometry('600x100')
    
        def quitting(self,event):
            print ('just passing through')
            quit()
            raise SystemExit

if __name__ == "__main__":
    app = App()
    frame = MainFrame(app)
    # app.withdraw()
    frame.bind('<Destroy>',app.quitting)
    app.mainloop()

綁定命令的頂級綁定執行多次

是的,這就是 tkinter 的工作原理。

當你綁定到某個東西時,你不會綁定到一個小部件。 相反,您綁定到綁定標簽 每個小部件都有一組綁定標簽 當一個小部件接收到一個事件時,tkinter 將檢查它的每個綁定標簽,看看是否有一個 function 綁定到它的給定事件。

那么,什么是小部件綁定標簽? 每個小部件都有綁定標簽“all”。 每個小部件還獲得一個以小部件本身命名的綁定標簽。 它獲得第三個綁定標簽,即小部件 class 的名稱(例如:“按鈕”、“標簽”等)。 第四個標簽——給你帶來麻煩的標簽——是包含小部件的 window 的名稱。 順序從最具體到最不具體:小部件、小部件 class、window、“全部”。

您可以通過打印小部件的綁定標簽來查看這一點。 考慮以下代碼:

import tkinter as tk

root = tk.Tk()
toplevel = tk.Toplevel(root)
label = tk.Label(toplevel)
print(f"binding tags for label: {label.bindtags()}")

運行時,上面的代碼會生成這個 output:

binding tags for label: ('.!toplevel.!label', 'Label', '.!toplevel', 'all')

第一個字符串..toplevel.!label是 label 小部件的內部名稱。 Label是小部件 class, .!toplevel是頂層小部件的名稱,然后是字符串all

當您點擊 label 時會發生什么? 首先,tkinter 將檢查是否有綁定按鈕單擊標簽..toplevel.!label 如果您綁定到小部件本身,它將有一個。 接下來,它將檢查小部件 class 上是否存在綁定。 滾動條和按鈕等小部件將在小部件 class 上具有綁定,但 label 不會。 接下來,tkinter 將查看 window 本身是否有針對該事件的綁定。 最后,它會查看特殊標簽all上是否有綁定。

您可以通過將綁定標簽列表傳遞給bindtags命令來更改小部件的綁定標簽。 例如,如果您希望每個小部件都有一個框架的綁定標簽,您可以設置綁定標簽以包含框架,然后每個小部件都會響應綁定到框架的事件。

您也可以使用相同的技術來刪除綁定。 例如,如果您想從Text小部件中刪除所有默認綁定,則可以從其綁定標簽列表中刪除Text 一旦你這樣做了,小部件將不會響應任何按鍵或按鍵釋放。

綁定標簽如何工作的規范描述在 tcl/tk 的bindtags 手冊頁中。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM