Daniel B.
Daniel B.

Reputation: 1273

packing using tkinter in_ keyword doesn't work with widgets created outside of a frame subclass

My understanding is that the in_ keyword argument to pack/grid should allow me to specify the managing widget. I want to pack arbitrary widgets inside a Frame subclass, so I passed the widgets and packed them during intialization, but the widgets didn't appear (although space in the window appears to have been allocated...). If I create the widget internally using master which is root, there is no issue and the widgets are displayed as expected.

The following working example and its output demonstrate the issue:

import tkinter as tk
from tkinter import ttk

class ItemContainerExternal(ttk.Frame):
    def __init__(self, master, input_label, input_object):
        ttk.Frame.__init__(self, master)
        self.label = input_label
        self.label.pack(side=tk.LEFT, padx=5, pady=3, fill=tk.X, in_=self)
        self.input_object = input_object
        self.input_object.pack(side=tk.LEFT, padx=5, pady=3, fill=tk.X, in_=self)

    def get(self):
        return variable.get()

class ItemContainerInternal(ttk.Frame):
    def __init__(self, master):
        ttk.Frame.__init__(self, master)
        ttk.Label(master, text='internal').pack(side=tk.LEFT, padx=5, pady=3, fill=tk.X, in_=self)
        self.input_object = ttk.Entry(master)
        self.input_object.pack(side=tk.LEFT, padx=5, pady=3, fill=tk.X, in_=self)

    def get(self):
        return variable.get()

if __name__ == '__main__':
    root = tk.Tk()
    inputobj = ttk.Entry(root)
    inputlabel = ttk.Label(root, text='external')
    ItemContainerExternal(root, inputlabel, inputobj).grid(row=0, column=0)
    ItemContainerInternal(root).grid(row=1, column=0)
    root.mainloop()

enter image description here

Upvotes: 0

Views: 300

Answers (2)

GaryMBloom
GaryMBloom

Reputation: 5690

The order in which widgets get created matters. Newer widgets are "on top of" previous widgets.

Call .lower() on the Frame after you create it, assuming it's created after all the widgets that you will pack into it. If not, you'll need to either call .lower() again on the Frame after creating a new widget to go inside it, or you'll have to raise the new widget via .lift() as per Bryan's answer.

Upvotes: 1

Bryan Oakley
Bryan Oakley

Reputation: 386240

The problem is that you're creating the entry and label before you're creating the frame, so they have a lower stacking order. That means the frame will be on top of the entry and label and thus, obscuring them from view.

A simple fix is to call lift() on the entry and label:

class ItemContainerExternal(tk.Frame):
    def __init__(self, master, input_label, input_object):
        ...
        self.input_object.lift()
        self.label.lift()

screenshot

Upvotes: 2

Related Questions