have a toplevel window always appear at the same place

85 Views Asked by At

I have the following code where there's a rectangle drawn on a canvas. The rectangle is where I want it to be. I want the rectangle as a border for the toplevel window. How do I make the toplevel window always appear on the same place by taking the coordinates of the rectangle. I tried to take the coordinates in the following, but it doesn't work

import tkinter as tk

class PageOne(tk.Frame):
    def __init__(self, parent, *args, **kwargs):
        super().__init__(parent, *args, **kwargs)
        self.toolbar1 = tk.Frame(self,background='#393951', height=30)
        self.sidepanel = tk.Frame(self,background='#192232', padx=15, pady=5)
        self.sidebtnfrm1 = tk.Frame(self,background='#192232', padx=15, pady=5)
        self.sidebtnfrm2 = tk.Frame(self,background='#192232', padx=15, pady=5)
        self.main1 = tk.Frame(self,background='#192232')
        self.main2 = tk.Frame(self,background='#192232')

        self.grid_rowconfigure(1, weight=15, uniform=True)
        self.grid_rowconfigure(2, weight=1, uniform=True)
        self.grid_rowconfigure(3, weight=1, uniform=True)
        self.grid_columnconfigure(0, weight=2, uniform=True)
        self.grid_columnconfigure(1, weight=6, uniform=True)
        self.grid_columnconfigure(2, weight=5, uniform=True)

        self.toolbar1.grid(row=0, column=0, columnspan=3, sticky="nsew")
        self.sidepanel.grid(row=1, column=0, sticky="nsew")
        self.sidebtnfrm1.grid(row=2, column=0,sticky="nsew")
        self.sidebtnfrm2.grid(row=3, column=0,sticky="nsew")
        self.main1.grid(row=1, column=1, rowspan=3,sticky="nsew")
        self.main2.grid(row=1, column=2, rowspan=3,sticky="nsew")
        
        self.canvas0 = tk.Canvas(self.main1,background="#192232",highlightthickness=0,width=self.main1.winfo_screenwidth()//6,height=self.main1.winfo_screenheight()//1.7)
        self.canvas0.pack(fill="both", pady=25)
        self.canvas0.create_rectangle(10,10,206,206,fill="#192232", outline="#8c92ac",width=2,tags=("rectangle",))
        self.canvas0.bind("<Configure>", self.resize_canvas_objects)
        
        submit_btn = tk.Button(self.sidebtnfrm2,text="Submit",command=lambda: top(self))
        submit_btn.pack(side="left")
        
        def top(self):
            x1, y1, x2, y2 = self.canvas0.bbox("rectangle")
            rect_width = x2 - x1
            rect_height = y2 - y1
            topi = tk.Toplevel(self, width=rect_width, height=rect_height)
            titlebar_height = topi.winfo_reqheight() - rect_height
            y1 -= titlebar_height
            topi.geometry(f'+{self.main1.winfo_rootx()+x1}+{self.main1.winfo_rooty()+y1}')  
            topi.attributes('-topmost', True)
            topi.attributes('-topmost', False)
    
    def resize_canvas_objects(self, event):
        self.canvas0 = event.widget
        x0, y0 = (2, 2)
        x1, y1 = (event.width-0, event.height)
        print(x1,y1)
        self.canvas0.coords("rectangle", x0, y0, x1, y1)
        self.canvas0.configure(scrollregion=self.canvas0.bbox("all"))

root = tk.Tk()
root.wm_state('zoomed')
p1 = PageOne(root)
p1.pack(fill="both", expand=True)
root.mainloop()
1

There are 1 best solutions below

0
Derek On

This code produces the desired effect but positioning is finicky. The Toplevel window sits inside the rectangle with size determined by w, h.

import tkinter as tk

root = tk.Tk()
root.withdraw()

wide = root.winfo_screenwidth() - 8
high = root.winfo_screenheight() - 8
root.geometry(f"{wide}x{high}+4+4")

def closer(*event):
    root.destroy()

root.protocol("WM_DELETE_WINDOW", closer)
root.bind("<Escape>", closer)

# essential
root.rowconfigure(0, weight = 1)
root.columnconfigure(0, weight = 1)

canvas = tk.Canvas(root)
canvas.grid(sticky = tk.NSEW)

# set size
w, h = 400, 400
pos = int(w * 0.5), int(h * 0.5), int(w * 1.5), int(h * 1.5)
square = canvas.create_rectangle(*pos, fill = "red", outline = "white")

root.deiconify()
root.wait_visibility()
# essential
root.update()

xx = root.winfo_rootx() - root.winfo_x() - 3
yy = root.winfo_rooty() - root.winfo_y() + 4

W = int(canvas.coords(square)[2] - canvas.coords(square)[0] - xx)
H = int(canvas.coords(square)[3] - canvas.coords(square)[1] - yy)

X = int(canvas.winfo_rootx() + canvas.coords(square)[0] - xx)
Y = int(canvas.winfo_rooty() + canvas.coords(square)[1] + 2) # ??

top = tk.Toplevel(root)
top.withdraw()
top.geometry(f"{W}x{H}+{X}+{Y}")
top.transient(root)

top.deiconify()
top.wait_visibility()

root.mainloop()