【问题标题】:tkinter - undock frame and handle window close eventtkinter - 取消停靠框架并处理窗口关闭事件
【发布时间】:2021-12-27 17:52:15
【问题描述】:

基于this question,我写了以下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 的类型是 而不是 TopLevel,因为 wm manage documentation 说:指定的小部件将成为独立的顶部级窗口
  2. 由于 self.dockable_frame.protocol("WM_DELETE_WINDOW", insert_function_here) 在我的 Windows 电脑上出现错误,我该如何处理窗口关闭事件?

错误是:
AttributeError:“框架”对象没有属性“协议”
我理解错误但如何处理窗口关闭事件?

【问题讨论】:

  • 你大概可以self.dockable_frame.bind('<Destroy>', insert_function_here)来处理销毁;至于为什么它不是专门的Toplevel?文档并没有说它必须成为Toplevel,只是它确实成为的顶级窗口

标签: python tkinter events window


【解决方案1】:

文档具有误导性。 As I discovered this feature 我想的差不多,框架变成了窗户。事实上,这不是真的,我可以通过下面的代码证明这一点。

真正发生的情况是,至少在 MS-Windows 下,但我希望在其他操作系统下具有相同的功能,框架将被打包在 wm_mange 为此创建的不同顶层上。

当 tkinter 定义 Window/Toplevel 时,它总是为您将使用的 client area 构建一个 child window (frame)。这就是为什么你需要在 change your window style 时调用 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

reference:

在 Tk 中,顶层窗口基本上是一种特殊形式的框架,它 由窗口管理器管理。建议是添加命令 wm manage 和 wm forget 哪个会采用任意 Frame 并允许 它由窗口管理器管理,使其成为顶层窗口。

【讨论】:

    【解决方案2】:

    为什么 self.dockable_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)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-04-02
      • 1970-01-01
      • 1970-01-01
      • 2019-03-27
      相关资源
      最近更新 更多