2017-02-23 105 views
2

私は必要に応じて開くことができる1つのメインウィンドウと1つ以上のToplevel()ウィンドウが必要です。私は窓を作り、それらを破壊することさえできます。Python3/tkinterで、ユーザーがToplevelウィンドウの閉じるボタンをクリックしたときにインターセプトする方法

しかし、私はメインウィンドウにボタンを実装しようとしていますが、第2のウィンドウを開いたり閉じたりします(その第2のウィンドウは常に一意である必要があります。これは少しいじった後、私は、今持っているものです。

#!/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() 

今、ユーザーがウィンドウを閉じるボタン、または対応するキーボードショートカットをクリックした場合、アプリは、第二の窓はもう存在しないことを知ることができませんウィンドウを開閉するためにボタンを押すと何も起こりません。また、開いている/閉じるボタンを押し続けると、ボタンが2番目のウィンドウを開いていないことがあります。私は間違って何をしていますか?

答えて

4

トップレベルウィジェットの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ウィンドウでAlt-F4も呼び出されます。

Tk documentationがあります。私が見つけたpythonのドキュメントは、むしろ疎そうでした。

+0

これは、メイン(ルート)ウィンドウでのみ機能するようです。たとえば、アプリケーションを終了する前に確認ダイアログを表示することができます。しかし、ユーザーが2番目のウィンドウを閉じたときに、何らかのメソッドや関数を呼び出すことができません。それを行う方法はありますか? –

+1

同じテクニックはトップレベルのウィジェットすべてに対して機能します。あなたはそれぞれのトップレベルに 'wm_protocol'を呼び出さなければなりません。ルートトップレベルは、別のダイアログウィンドウのメッセージをキャッチしません。 – patthoyts

+0

各トップレベルでそれを呼び出す構文は何でしょうか? 'self.wm_protocol(" WM_DELETE_WINDOW "、lambda:print(" oww "))'のように追加すると、オブジェクトにその属性がないというエラーが表示されます... –

0

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() 
関連する問題