Winfo_y does not return correct value Winfo_y does not return correct value tkinter tkinter

Winfo_y does not return correct value


You can avoid all of the math by using relative placement. When you use place, you can specify that the listbox is relative to the entry widget.

For example:

self.listbox.place(in_=self, relx=0, rely=1.0, bordermode="outside", relwidth=1.0, anchor='nw')
  • in_ specifies which widget to be relative to
  • relx is a floating point value representing the relative x position. 0 == left edge, 1.0 == right edge
  • rely is a floating point value represeenting the relative y position. A value of 1 means at the bottom of the widget
  • bordermode means to treat the coordinates relative to the outside border than inside the border
  • relwidth means to make the widget as wide as the entry widget.

screenshot


So the issue was with the label frame. I have now modified my code to check if the master widget is a label frame. If it is a label frame then I subtract the height of the font of the label frame from the y coordinate.

I calculate the height of the font using the answer to this question: (Measure the height of a string in Tkinter Python?)

I also check if it is a frame and then subtract the border width.

Updated code:

class TestEntry(tk.Entry):    def __init__(self, top):        self.window = top        tk.Entry.__init__(self, self.window)        self.listshown = False        self.bind('<FocusIn>', self.showlist)        self.bind('<FocusOut>', self.hidelist)    def showlist(self, event):        if not self.listshown:            x = self.winfo_x()            y = self.winfo_y()            h = self.winfo_height()            w = self.winfo_width()            y = y + h            # If the master widget is a label frame then substract the height of the frame font from y coordinate            if 'labelframe' in self.winfo_parent():                print('master is a label frame')                height_font = tkf.Font(font=self.master['font']).metrics('linespace')                y = y - height_font            # If the master widget is any kind of frame then substract the border width of the frame from x & y            if 'frame' in self.winfo_parent():                print('master is a frame')                width_border = self.master['borderwidth']                x = x - int(width_border)                y = y - int(width_border)            self.listbox = tk.Listbox(self.master, highlightbackground='blue', highlightthickness=1)            self.listshown = True            self.listbox.place(x=x, y=y, width=w, anchor='nw')            self.listbox.update()    def hidelist(self, event):        if self.listshown:            self.listbox.destroy()            self.listshown = Falseif __name__ == "__main__":    root = tk.Tk()    root.geometry('800x800')    frame = tk.Frame(root, relief='groove', borderwidth=10)    frame.pack(padx=30, pady=30, fill='both', expand=True)    TestEntry(frame).pack(side='top', padx=40)    label_frame = tk.LabelFrame(root, text="Label Frame", borderwidth='10', font=('Google Sans', 40, 'bold underline'))    label_frame.pack(padx=30, pady=30, fill='both', expand=True)    TestEntry(label_frame).pack(side='top', padx=40)    root.mainloop()

enter image description here