簡體   English   中英

tkinter - 取消停靠框架並處理窗口關閉事件

[英]tkinter - undock frame and handle window close event

基於這個問題,我寫了以下mwe:

import tkinter as tk


class BaseFrame(tk.Frame):
    def __init__(self, parent):
        tk.Frame.__init__(self, parent)
        self.parent = parent
      
        self.bmanage = tk.Button(self, text='undock', command = self.undock)
        self.bforget = tk.Button(self, text='dock', command = self.dock)

        self.bmanage.grid(row=0, column=0, padx=20, pady=20, sticky='nsew')
        self.bforget.grid(row=0, column=1, padx=20, pady=20, sticky='nsew')

        self.dockable_frame = tk.Frame(self, bg="red", height=100)
        self.dockable_frame.grid(row=1, column=0, padx=20, pady=20, columnspan=2, sticky='nsew')
        self.label = tk.Label(self.dockable_frame, text="hi")
        self.label.grid(row=0, column=0, padx=150, pady=20, sticky='nsew')

    def undock(self):
        self.parent.wm_manage(self.dockable_frame)
        self.dockable_frame.configure(bg='blue')

        print(type(self.dockable_frame))

    def dock(self):
        self.parent.wm_forget(self.dockable_frame)
        self.dockable_frame.grid()


if __name__ == "__main__":
    root = tk.Tk()

    base_frame = BaseFrame(root)
    base_frame.grid(row=0, column=0, padx=20, pady=20, sticky='nsew')
    
    root.mainloop() 

單擊取消停靠按鈕,取消停靠紅框,單擊停靠按鈕,再次停靠該框。 我有兩個問題:

  1. 為什么 self.dockable_frame 的類型是<class 'tkinter.Frame'>而不是 TopLevel 因為wm 管理文檔說:指定的小部件將成為獨立的頂級窗口
  2. 由於self.dockable_frame.protocol("WM_DELETE_WINDOW", insert_function_here)在我的 Windows 電腦上出現錯誤,我該如何處理窗口關閉事件?

錯誤是:
AttributeError: 'Frame' 對象沒有屬性 'protocol'
我理解錯誤但如何處理窗口關閉事件?

為什么 self.dockable_frame 的類型是 <class 'tkinter.Frame'> 而不是 TopLevel 因為 wm 管理文檔說:指定的小部件將成為獨立的頂級窗口?

我認為這是因為self.dockable_frame是一個 python 類並且不知道底層小部件已更改。 可以說這是wm_manage一個錯誤。

由於 self.dockable_frame.protocol("WM_DELETE_WINDOW", insert_function_here) 在我的 Windows PC 上出現錯誤,我該如何處理窗口關閉事件?

最簡單的方法是直接從tk.Wm類調用該方法。 它看起來像這樣:

tk.Wm.protocol(self.dockable_frame, "WM_DELETE_WINDOW", self.whatever)

該文檔具有誤導性。 當我發現這個我認為類似的功能時,框架變成了一個窗口。 事實上,這不是真的,我可以通過下面的代碼證明這一點。

真正發生的事情,至少在 MS-Windows 下,但我希望在其他操作系統下具有相同的功能,就是幀將被打包在 wm_mange 為此創建的不同頂層上。

當 tkinter 定義一個Window/Toplevel 時,它總是為您將使用的客戶區構建一個子窗口(框架) 這就是為什么你需要調用 win32gui。 當您將更改窗口樣式時,請使用GetParent方法。

代碼:

import tkinter as tk
import win32gui

def info():
    print(f'python id: {id(frame)}')
    print(f'tkinterID: {frame.winfo_id()}')
    print(f'parent id: {win32gui.GetParent(frame.winfo_id())}')
def undock():
    root.wm_manage(frame)
def forget():
    root.wm_forget(frame)
    frame.pack()

root = tk.Tk()
frame= tk.Frame()
frame.pack()

b1 = tk.Button(frame,text='INFO',command=info)
b2 = tk.Button(frame,text='mnge',command=undock)
b3 = tk.Button(frame,text='nrml',command=forget)
b1.pack()
b2.pack()
b3.pack()

root.mainloop()

輸出:

通過第一次出現

python id: 67118160
tkinterID: 3412074
parent id: 7867926

脫離后

python id: 67118160
tkinterID: 3412074
parent id: 15666896

忘記之后

python id: 67118160
tkinterID: 3412074
parent id: 7867926

參考

在 Tk 中,Toplevel 窗口基本上是由窗口管理器管理的 Frame 的特殊形式。 建議是添加命令 wm manage 和 wm forget ,它們將采用任意 Frame 並允許它由窗口管理器管理,使其成為 Toplevel 窗口。

暫無
暫無

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

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