Tkinter : How To Create A Listbox That Can Appear And Disappear Over Another Widget Without Moving The Other Widget?
Solution 1:
If you want to position an widget such that it doesn't affect any other widgets, you should use place
. One of the nice things about place
is that it both lets you place widgets relative to other widgets, and set the width and height relative to other widgets.
For example, to place the listbox window (including its containing frame) immediately below the widget that triggered it to appear, you could use place
like this:
self.lbframe.place(in_=event.widget, x=0, rely=1, relwidth=1.0, anchor="nw")
The relwidth
option says that we want the frame containing the listbox to be exactly as wide as the entry widget. This is optional, but it illustrates the type of control you have with place
. The in_
parameter specifies which widget the width is relative to.
Because place
doesn't affect other children of the same parent, you must make sure that the parent window is large enough to show the list. Since list is an embedded widget, it won't float above the window. In your case that won't happen because your App
instance doesn't fill the whole window. The reason it doesn't is because you neglect to give any rows or columns in the root window any weight.
grid
is great at what it does, but sometimes it is the wrong tool for the job. For example, since App
is the only widget inside the root window, using pack
means you can get it to fill the window with a single command. Using grid
requires at lest three (two of which you forgot to call). For that reason, I recommend using pack
to put App
inside root
. That's not necessary for getting place
to work, it just makes your code easier to understand.
I also recommend not having App
be responsible for placing itself in its parent. You can, and again, it won't affect how place
works, but it will make your code easier to understand because you don't have one function (App.__init__
) responsible for laying out both the main window and its children.
With all that in mind, the following is a working solution based off of your code. Note: there is also a bug in how you are assigning values to the listbox, but fixing that is beyond the scope of this question.
#!/usr/bin/python3# -*- coding: utf-8 -*-try:
import tkinter as tk # Python 3 tkinter modulesexcept ImportError:
import Tkinter as tk # Python 2 tkinter modulesclassApp(tk.Frame):
def__init__(self, parent):
tk.Frame.__init__(self, parent)
self.toggle = True
self.label1 = tk.Label(self, text = 'Click me to see Names of Famous Folks')
self.label2 = tk.Label(self, text = 'The World of Famous Folks! Welcome!')
self.label1.grid(row=0, column=0, sticky='nsew', pady=10)
self.label2.grid(row=2, column=0, sticky='nsew')
nlist1 = ['Peter', 'Scotty', 'Walter', 'Scott', 'Mary']
self.lbframe = tk.Frame(self)
self.lbframe.list_values = tk.StringVar()
self.lbframe.list_values.set(nlist1)
self.lbframe.list= tk.Listbox(self.lbframe, height=5, width= 10,
listvariable=self.lbframe.list_values)
self.lbframe.list.pack(fill="both", expand=True)
self.label1.bind("<Button-1>", self.ShowHideListbox)
defShowHideListbox(self, event):
if self.toggle: # Show
self.toggle=False
self.lbframe.place(in_=event.widget, x=0, rely=1, relwidth=1.0, anchor="nw")
else: # Hide
self.toggle=True
self.lbframe.place_forget()
if __name__ == '__main__':
root = tk.Tk()
root.geometry("400x200")
app = App(root)
app.pack(fill="both", expand=True)
app.mainloop()
Post a Comment for "Tkinter : How To Create A Listbox That Can Appear And Disappear Over Another Widget Without Moving The Other Widget?"