I am trying to create a custom entry widget in tkinter. When this entry has focus it should display a listbox right under the entry widget with some options to the user. When it loses focus the listbox should delete by itself.
This is what I have:
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()
# Print bottom left x and y of the entry
print(x, y, h)
self.listbox = tk.Listbox(self.master, highlightbackground='blue', highlightthickness=1)
self.listshown = True
self.listbox.place(x=x, y=y + h, width=w,anchor='nw')
self.listbox.update()
# Print top left x,y of listbox
x = self.listbox.winfo_x()
y = self.listbox.winfo_y()
print(x, y)
def hidelist(self, event):
if self.listshown:
self.listbox.destroy()
self.listshown = False
if __name__ == "__main__":
root = tk.Tk()
root.geometry('500x500')
frame = tk.LabelFrame(root, text='Frame')
frame.pack(padx=30, pady=30, fill='both', expand=True)
TestEntry(frame).pack(side='left', padx=20, pady=20)
tk.Entry(frame).pack(side='left', padx=20, pady=20)
This is the output that I see:
22 218 19
24 254
As you can see in the image below, instead of appearing at the left bottom corner of the entry box, listbox appears further below. Why is this happening?
EDIT: This issue only happens when I put my widget in a label frame as shown in the code above. When I put it in a regular frame this does not happen.
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 torelx
is a floating point value representing the relative x position. 0 == left edge, 1.0 == right edgerely
is a floating point value represeenting the relative y position. A value of 1 means at the bottom of the widgetbordermode
means to treat the coordinates relative to the outside border than inside the borderrelwidth
means to make the widget as wide as the entry widget.