#1
  1. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Feb 2013
    Location
    California, USA
    Posts
    76
    Rep Power
    2

    KeyPress Trapping Between 2 Classes


    I need help in trying to understand how to use binding
    to trap for keystrokes where a parent and a child window
    accept the same character (c) to close the window.

    In the code below, when 'c' is entered to close the child
    window, the parent window closes from the same event
    that closed the child window.

    How do you get the parent window to ignore events
    resulting from bindings in the child window?

    Thankyou.
    Code:
    from tkinter import *
    import win32gui    #Edit: omitted
    
    root = Tk()
    root.geometry('500x460+20+20')
    
    class main_form():
    
        def __init__(self, root):
            self.frame = Frame(root, width=400, height=260,
                bg='Wheat2', borderwidth=2, relief=GROOVE)
            self.frame.pack()
            self.frame.place(x=50, y=100)
    
            self.mLabel = Label(self.frame, text='Main Window', font=('Helvetica', 18))
            self.mLabel.place(x=120, y=100) 
    
            newWindowBtn = Button(text='Click to\nOpen New Window or type \'o\'',
                command=self.open_newWindow, 
                font=('Helvetica', 14), padx=4, pady=4)
            newWindowBtn.pack(side=TOP, anchor=S)
        
            closeBtn = Button(text='Click to\nClose Main Window or type \'c\'',
                command=self.close_mainWindow,
                font=('Helvetica', 14), padx=4, pady=4)
            closeBtn.pack(side=BOTTOM, expand=YES, anchor=S)
    
            root.bind('<KeyPress>', self.key_pressed)
    
            try:  #Edited: change 'self.top' to 'root'
                root.protocol("WM_DELETE_WINDOW",  self.close_mainWindow)
            except:
                pass
            
        def key_pressed(self,event):
            if event.keysym.lower()=='o':
                self.open_newWindow()
            elif event.keysym.lower()=='c':
                self.close_mainWindow()
    
        def open_newWindow(self):
            newWindow = child_form()
            
        def close_mainWindow(self):
            print('\ngoing through root.destroy()')
            root.destroy()
            
    class child_form():
    
        def __init__(self):
            self.top = Toplevel()
            self.top.geometry('500x460+20+20')
            
            self.frame = Frame(self.top, width=400, height=260, borderwidth=2,
                bg='SeaGreen1', relief=GROOVE)
            self.frame.pack()
            self.frame.place(x=50, y=100)
    
            self.top.cLabel = Label(self.frame, text='Child Window', font=('Helvetica', 18))
            self.top.cLabel.place(x=125, y=100)   
    
            self.top.bind('<KeyPress>', self.key_pressed)
    
            self.top.closeBtn = Button(self.top, text='Click to\nClose Child Window or type \'c\'',
                command=self.close_childWindow,              
                bg='NavajoWhite1', font=('Helvetica', 14), padx=4, pady=4)
            self.top.closeBtn.pack(side=BOTTOM, anchor=S)
    
            try:
                self.top.protocol("WM_DELETE_WINDOW", self.close_childWindow)
            except:
                pass
            
        def key_pressed(self,event):
            if event.keysym.lower()=='c':
                self.close_childWindow()
    
        def close_childWindow(self):
            self.top.destroy()   
                
    app = main_form(root)
    
    root.mainloop()
  2. #2
  3. Contributing User
    Devshed Demi-God (4500 - 4999 posts)

    Join Date
    Aug 2011
    Posts
    4,851
    Rep Power
    481
    Search internet for

    tkinter event propagate
    [code]Code tags[/code] are essential for python code and Makefiles!
  4. #3
  5. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Feb 2013
    Location
    California, USA
    Posts
    76
    Rep Power
    2
    b4...after a day of searching for articles on propagate, I have
    come to the conclusion that my application of propagate is a
    well-kept secret. But hey, tomorrow's another day

    I'm ready for the next clue.

    The code below almost does it; it keeps window #1 open when
    window #2 is closed, but as soon as I open window #2, the
    focus goes to idle, or to somewhere unknown if I double-click to
    run the code. I have to click on window #2 get the focus back
    to make it work as expected: either close by entering 'c' or close
    at the click of the close button. But I found no way to put
    'propagate' to work. The suggested use of return 'break' to
    prevent binding conflicts made no difference.

    I await more guidance.
    Code:
    from tkinter import *
    import win32gui
    
    root=Tk()
    
    w,h,x,y = 450,350,20,20
    
    root.wm_geometry("%dx%d+%d+%d" % (w, h, x, y))
    
    class main_window():
    
        def __init__(self, root):
            self.main_label = Label(root, text='Main Window',
                font=('Helvetica', 24), padx=20, pady=20)
            self.main_label.place(x=100, y=100)
    
            self.main_btn1 = Button(root, text='Click to\nOpen New Window\nor Type \'o\'',
                    bg='Orange', font=('Helvetica', 12))
            self.main_btn1.pack(side=TOP, anchor=S)
    
            self.main_btn1.config(command=self.open_new_window)
            
            self.main_btn2 = Button(root, text='Click to\nClose Main Window\nor Type \'c\'',
                    bg='LightCyan', font=('Helvetica', 12))
            self.main_btn2.pack(side=BOTTOM, anchor=S)
    
            self.main_btn2.config(command=self.close_window)
            
            root.bind('<KeyPress>', self.handle_event)
    
        def handle_event(self, event):
            if event.keysym.lower()=='o':
                self.open_new_window()
            elif event.keysym.lower()=='c':
                self.close_window()
       
        def open_new_window(self):
            root.withdraw()    #hide main window until child window is closed
            new_window = child_window()
            
        def close_window(self):
            root.destroy()
    
    class child_window():
    
        def __init__(self):
            self.top = Toplevel()
            self.top.geometry('450x350+20+20')
            self.top.bind('<KeyPress>', self.handle_event)
            
            self.frame = Frame(self.top, width=350, height=220, borderwidth=2,
                bg='SeaGreen1', relief=GROOVE)
            self.frame.pack()
    
            self.frame.place(x=40, y=50)
            
            self.top.top_label = Label(self.frame, text='Child Window',
                font=('Helvetica', 24), fg='Blue', padx=20, pady=20)
            self.top.top_label.place(x=50, y=60)
    
            self.top.close_btn = Button(self.top, text='Click to\nClose Child Window\nor Type \'c\'',
                command=self.close_window,
                bg='NavajoWhite1', font=('Helvetica', 12), padx=4, pady=4)
            self.top.close_btn.pack(side=BOTTOM, anchor=S)
            self.top.close_btn.bind('<KeyPress>', self.handle_event)
            
            try:
                self.top.protocol("WM_DELETE_WINDOW", self.close_window)
            except:
                pass
    
            self.top.focus_force()  #Edit: this solved the issue of the window's losing focus
            
        def handle_event(self, event):
            if event.keysym.lower()=='c':
                self.close_window()
                    
        def close_window(self):
            root.update()
            root.deiconify()
        
            self.top.destroy()
            
    mw = main_window(root)
    
    root.mainloop()
    Edited: 'self.protocol...' changeed to 'self.top.protocol...' to fix window #1 not reappearing when #2 windows close icon clicked.
  6. #4
  7. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    May 2009
    Posts
    487
    Rep Power
    33
    Do not run a tkinter program in Idle. Idle is written in tkinter so the results are unpredictable. You should be able to use focusin or widget.focus_get() to see which widget has focus. But since you have a GUI you should consider clicking a button to close a particular window. I would guess that a button is what most everyone does, so if there is not much help on this question that is why.
    Last edited by dwblas; September 16th, 2013 at 10:29 PM.
  8. #5
  9. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Feb 2013
    Location
    California, USA
    Posts
    76
    Rep Power
    2
    dwblas, this was an educational exercize. I know that buttons
    are essential for applications but I wanted to try a simple
    experiment for a mouseless computer.

    Your tip lead me to focus_force(). When I put it in my code last
    posted, which I edited in this thread, it worked. Window #2 got
    the focus, both in idle and when run from Explore.

    If anyone is willing to share your knowledge about 'propagate'
    when used to resolved binding conflicts (if there is such a
    thing), or know of a web source that gives the details and
    example use, I welcome your reply. As I have already said,
    the code return 'break' placed at the end of the code for an
    event handling, did nothing to stop window #1 events from
    occurring when window #2 was visible.
    I noticed that when window #2 was opened from the main
    class, the program flow continued on in the main class, as
    evidenced by a print statement. My guess was that program
    flow would have stopped , then resumed after #2 closed. But
    not so. Time and Python wait for no man.
    Thanks.

IMN logo majestic logo threadwatch logo seochat tools logo