Make Toplevel window pop up to the top when root window clicked

2.1k views Asked by At

I have a UI root window where two other Toplevel windows get created on separate button clicks. These Toplevel windows are anchored to the root window and drag along the screen with the root window.

My problem is if i have another window open and my UI is hiding behind it, if i click on my UI from the taskbar or the little i can see on the screen, only the root Tk window pops up and the other Toplevel windows are still hiding behind the other window.

I tried toplevel.lift() and toplevel.wm_attributes("-topmost", 1) but neither give me what i want.

How can I tie the Toplevel windows so that if they are open and I click on the root window the Toplevel window also pops to the top?

2

There are 2 answers

4
Mike - SMT On BEST ANSWER

Here is a simple example that will open 2 windows and disable everything on the root window while also binding any interaction with that root window to lift all the top windows above it.

I have also bound the top level close event to first remove the root binding and then destroy the top levels then re-enable all the widgets in the root window. this should serve to be an antiquity example of what you are trying to do.

Let me know if you have any questions.

import tkinter as tk


class ExampleApp(tk.Frame):
    def __init__(self, master):
        tk.Frame.__init__(self, master)
        self.master = master
        self.master.geometry("400x150")
        self.main_frame = tk.Frame(self.master)
        self.main_frame.pack(expand=tk.YES, fill=tk.BOTH)
        self.master.protocol('<WM_LBUTTONDBLCLK>', self.motion)
        tk.Label(self.main_frame, text = "This is the main window").pack()
        tk.Button(self.main_frame, text = "Open 2 top level windows!", command = self.open_windows).pack()

    def motion(self, event):
        x, y = event.x, event.y
        print('{}, {}'.format(x, y))

    def open_windows(self):
        self.top1 = tk.Toplevel(self.master)
        self.top2 = tk.Toplevel(self.master)
        self.top1.geometry("100x100")
        self.top2.geometry("100x100")
        # ties the window close event to our customer close method for toplevel
        self.top1.protocol("WM_DELETE_WINDOW", self.close_toplevels)
        self.top2.protocol("WM_DELETE_WINDOW", self.close_toplevels)
        self.master.bind("<Unmap>", self.icon_all)
        self.top1.bind("<Unmap>", self.icon_all)
        self.top2.bind("<Unmap>", self.icon_all)
        self.master.bind("<Map>", self.de_icon_all)
        self.top1.bind("<Map>", self.de_icon_all)
        self.top2.bind("<Map>", self.de_icon_all)

        for child in self.main_frame.winfo_children():
            child.configure(state='disable')

        tk.Label(self.top1, text ="Topwindow 1").pack()
        tk.Label(self.top2, text ="Topwindow 2").pack()

        # sets the top windows to their initial locations
        self.lock_top_to_root()

        #keeps the top windows in the specified locations compared to root window
        self.master.bind("<Configure>", self.lock_top_to_root)

    def withdraw_tops(self, event=None):
        self.top1.withdraw()
        self.top2.withdraw()

    def de_icon_tops(self, event=None):
        self.top1.deiconify()
        self.top2.deiconify()

    def icon_all(self, event=None):
        self.withdraw_tops()
        self.master.iconify()

    def de_icon_all(self, event=None):
        self.de_icon_tops()
        self.master.deiconify()
        self.lock_top_to_root()

    def lock_top_to_root(self, event=None):
        self.top1.lift() # lift both toplevel windows about root
        self.top2.lift()
        # places each top level at each side
        # this is not set up to compensate for the root being resized but can be if you need it to.
        self.top1.geometry('+{}+{}'.format(self.master.winfo_x()+10, self.master.winfo_y()+30))
        self.top2.geometry('+{}+{}'.format(self.master.winfo_x()+275, self.master.winfo_y()+30))

    def close_toplevels(self):
        # customer close method to reset everything
        self.master.unbind('<Configure>')
        self.master.unbind("<Unmap>")
        self.master.unbind("<Map>")
        self.top1.destroy()
        self.top2.destroy()
        for child in self.main_frame.winfo_children():
            child.configure(state='active')

root = tk.Tk()
my_example = ExampleApp(root)
root.mainloop()
0
Moe On

"transient" - Specifies a parent window for the Toplevel window. When set, the Toplevel window is treated as a transient window and stays on top of its parent.

class MyClass(TopLevel):
    def __init__(self, master):
        super().__init__()
        self.transient(master)