0

I've encountered the problem, that I can not create a child widget of a child widget. I've tried using a class to create a window with widgets and alternatively a function to see if I don't understand something about how classes work, but the failure was the same.

I've boiled down the issue to the following code:

import tkinter as tk

root = tk.Tk()
root.geometry('900x400')

frame1=tk.LabelFrame(root, text="frame1",width=800, height=400, bg='blue', bd=5).pack()
labelframe1=tk.LabelFrame(frame1, text="labelframe1",width=300, height=300, bg='green', bd=15).pack()
labelframe2=tk.LabelFrame(frame1, text="labelframe2",width=300, height=300, bg='yellow', bd=15).pack()

button1 = tk.Button(labelframe1,text="text").pack()

I don't get errors with this code, but the outcome is the same. Only the child of root is created, but not the children of the root child.

How can I create "grandchild" widgets?

Riccardo
  • 13
  • 4
  • Just by accident, I solved it. I formatted the pack() method into a separate line. It seems even though I found it in some half-hearted tutorials (which already contained other coding errors), the pack method doesn't seem to always work when attached to the end of the line with "somename = tk.Label(..." – Riccardo Nov 02 '21 at 17:28
  • 2
    Not that it doesn't work, it simply returns `None` and `None` as the parent will default to the root `Tk` instance. Does this answer your question? [Tkinter: AttributeError: NoneType object has no attribute ](https://stackoverflow.com/questions/1101750/tkinter-attributeerror-nonetype-object-has-no-attribute-attribute-name) – Matiiss Nov 02 '21 at 17:48
  • This sounds too wide and too abstract for me personally to understand, but after reading another answer, I understood what you mean. So, technically you did answer, but I needed more input. – Riccardo Nov 04 '21 at 15:02

1 Answers1

1

In python, x().y() returns the value of y(). Thus, when you do tk.LabelFrame(...).pack() it returns None. Therefore, when you do tk.Button(labelframe1, ...) it's the same as tk.Button(None, ..., which causes the button to be a child of the root window.

Bottom line, it's a best practice to separate widget creation from widget layout. I also personally find that grouping layout code together makes the code much easier to understand. I think it's also a good practice to explicitly define which side the widget is being packed into.

frame1=tk.LabelFrame(root, text="frame1",width=800, height=400, bg='blue', bd=5))
labelframe1=tk.LabelFrame(frame1, text="labelframe1",width=300, height=300, bg='green', bd=15)
labelframe2=tk.LabelFrame(frame1, text="labelframe2",width=300, height=300, bg='yellow', bd=15)
button1 = tk.Button(labelframe1,text="text")

frame1.pack(side="top")
labelframe1.pack(side="top")
labelframe2.pack(side="top")
button1.pack(side="top").
button1 = tk.Button(labelframe1,text="text").pack()
Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
  • Thank you Bryan! Thank you for the explanation as to the big why, because it almost had a flying-dutchman-quality to me that sometimes widgets show and sometimes they don't by placing the positioning method in the same line. And yes, I do find your formatting easy on the eye. I in turn find it easier to sort object-wise and not method-wise, but a method-wise formatting does look cleaner though. – Riccardo Nov 04 '21 at 14:51