在python3/tkinter中,当用户单击Toplevel窗口上的关闭按钮时,如何拦截



我想拥有一个主窗口和一个或多个可以按需打开的Toplevel()窗口。我能够创建窗户,甚至可以摧毁它们。

但是,我正在尝试在主窗口中实现一个按钮,该按钮都打开并关闭第二个窗口(第二个窗口应该始终是唯一的,即切勿同时打开两次)。这就是我现在摆弄了一点之后的东西:

#!/usr/bin/python3
import tkinter as tk
from tkinter import ttk
import tkinter.font

class baseApp(ttk.Frame):
    def __init__(self,master,*args,**kwargs):
        super().__init__(master,*args,**kwargs)
        self.master = master
        self.mainframe = ttk.Frame(master)
        self.topframe = ttk.Frame(self.mainframe, padding="5 8 5 5")
        self.topframe.pack(side=tk.TOP, fill=tk.X)
        self.mainframe.pack(side=tk.TOP, expand=True, fill=tk.BOTH)

class App(baseApp):
    def __init__(self,master,*args,**kwargs):
        super().__init__(master,*args,**kwargs)
        self.master = master
        self.button1 = ttk.Button(self.topframe,text="One",command=self.button_one)
        self.btn_remessas = ttk.Button(self.topframe,text="Open/close Toplevel window",command=self.create_window1)
        self.button1.grid(row=0,column=0)
        self.btn_remessas.grid(row=0,column=1)
        self.topframe.pack(side=tk.TOP, fill=tk.X)
        self.mainframe.pack(side=tk.TOP, expand=True, fill=tk.BOTH)
    def create_window1(self):
        if current_state.window2_open == False:
            self.newWindow2 = tk.Toplevel(self.master)
            self.newWindow2.geometry('600x500+680+0')
            self.newWindow2.title('Second window')
            self.janela_remessas = SecondWindow(self.newWindow2)
            current_state.window2_open = True              
        else:
            self.newWindow2.destroy()
            root.update_idletasks()
            current_state.window2_open = False
    def button_one(self):
        print("button 1 pressed")

class SecondWindow:
    def __init__(self,master,*args,**kwargs):
        #super().__init__(master,*args,**kwargs)
        self.mainframe = ttk.Frame(master, padding="5 8 5 5")
        self.topframe = ttk.Frame(self.mainframe)
        self.button1 = ttk.Button(self.topframe,text="button",command=self.button_function)
        self.button1.pack()                
        self.topframe.pack(side=tk.TOP, fill=tk.X)
        self.mainframe.pack(side=tk.TOP, expand=True, fill=tk.BOTH)
    def button_function(self, *event):
        print("user just pressed button")
    def close_window(self, *event): #Please fix me!
        current_state.window2_open = False
        self.destroy()

class AppStatus:
    def __init__(self):
        self.window2_open = False  

if __name__ == "__main__": 
    root = tk.Tk() 
    app = App(root) 
    current_state = AppStatus()
    root.configure(background='grey95')
    root.title('Application window')
    root.geometry('1000x760+0+0')
    root.bind_all("<Mod2-q>", exit)
    root.mainloop()

现在,如果用户单击"关闭窗口"按钮或相应的键盘快捷键,则该应用将不知道第二个窗口不再存在,因此当我们按下按钮打开/关闭窗口时,。另外,如果我们继续按打开/关闭按钮,则有时该按钮不打开第二个窗口。我在做什么错?

您想使用Toplevel小部件的wm_protocol方法。特别是使用WM_DELETE_WINDOW协议。

>>> import tkinter as tk
>>> root = tk.Tk()
>>> dlg = tk.Toplevel(root)
>>> dlg.wm_title("dialog")
''
>>> root.wm_protocol("WM_DELETE_WINDOW", lambda: print("close root"))
''
>>> dlg.wm_protocol("WM_DELETE_WINDOW", lambda: print("close dialog"))
''
>>> root.mainloop()
close dialog
close root

当我单击窗框关闭按钮(大红色X)时,最后一行是输出的。现在,当我单击此问题时,这也不会退出,并且在任何一个TK Windows上也被要求使用Alt-F4

TK文档还有更多话要说。我发现的Python文档似乎很稀疏。

在遵循Patthoyts的建议之后,仅发布完整的工作代码。

#!/usr/bin/python3
import tkinter as tk
from tkinter import ttk
import tkinter.font

class baseApp(ttk.Frame):
    def __init__(self,master,*args,**kwargs):
        super().__init__(master,*args,**kwargs)
        self.master = master
        self.mainframe = ttk.Frame(master)
        self.topframe = ttk.Frame(self.mainframe, padding="5 8 5 5")
        self.topframe.pack(side=tk.TOP, fill=tk.X)
        self.mainframe.pack(side=tk.TOP, expand=True, fill=tk.BOTH)

class App(baseApp):
    def __init__(self,master,*args,**kwargs):
        super().__init__(master,*args,**kwargs)
        self.master = master
        self.button1 = ttk.Button(self.topframe,text="One",command=self.button_one)
        self.btn_remessas = ttk.Button(self.topframe,text="Open/close Toplevel window",command=self.create_window2)
        self.button1.grid(row=0,column=0)
        self.btn_remessas.grid(row=0,column=1)
        self.topframe.pack(side=tk.TOP, fill=tk.X)
        self.mainframe.pack(side=tk.TOP, expand=True, fill=tk.BOTH)
    def create_window2(self):
        if current_state.window2_open == False:
            self.newWindow2 = tk.Toplevel(self.master)
            self.newWindow2.geometry('600x500+680+0')
            self.newWindow2.title('Second window')
            self.janela_remessas = SecondWindow(self.newWindow2)
            current_state.window2_open = True
            self.newWindow2.wm_protocol("WM_DELETE_WINDOW", lambda: self.close_window2())        
        else:
            self.close_window2()
    def close_window2(self, *event):
        print("closing window")
        root.update_idletasks()
        current_state.window2_open = False
        self.newWindow2.destroy()
    def button_one(self):
        print("button 1 pressed")

class SecondWindow:
    def __init__(self,master,*args,**kwargs):
        #super().__init__(master,*args,**kwargs)
        self.mainframe = ttk.Frame(master, padding="5 8 5 5")
        self.topframe = ttk.Frame(self.mainframe)
        self.button1 = ttk.Button(self.topframe,text="button",command=self.button_function)
        self.button1.pack()                
        self.topframe.pack(side=tk.TOP, fill=tk.X)
        self.mainframe.pack(side=tk.TOP, expand=True, fill=tk.BOTH)
    def button_function(self, *event):
        print("user just pressed button")
    def close_window(self, *event): #Please fix me!
        current_state.window2_open = False
        self.destroy()

class AppStatus:
    def __init__(self):
        self.window2_open = False  

if __name__ == "__main__": 
    root = tk.Tk() 
    app = App(root) 
    current_state = AppStatus()
    root.configure(background='grey95')
    root.title('Application window')
    root.geometry('1000x760+0+0')
    root.bind_all("<Mod2-q>", exit)
    root.mainloop()

最新更新