Skip to content Skip to sidebar Skip to footer

Tkinter : How To Create A Listbox That Can Appear And Disappear Over Another Widget Without Moving The Other Widget?

Question: I would like to create a listbox that would appear and disappear below label1 but it should not affect the position of label2, when label1 is clicked. How can this be don

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?"