0

Consider the following simple code:

    from tkinter import *

    mainFrame = Frame(parent, bd=5, bg="yellow").pack(expand=True,fill=BOTH)

    frameA = Frame(mainFrame, bd=5, bg="green").place(anchor=NW, relx=0, rely=0 , relwidth=1.0, height=40)
    my_label = Label(mainFrame, text="Hello world ", bg="red").place(in_=frameA, relx=0, anchor=NW, rely=0, relwidth=0.5)

    frameB = Frame(frameA, bd=5, bg="gold").place(in_=frameA , anchor=N, relx=0.5, rely=0.8, width=30, height=50)

The result looks like this: enter image description here

The yellow frame makes sense and is what I expected. The same goes for frameA (green) and my_label.

However, frameB refuses to do what I expect, originally I have rely=1.0 for its place command and I was expecing it's N (top center edge) to be placed at the horizontal midpoint of the bottom (1.0*height) of the green frame which I have set up to be both its parent and used as it .place() command _in parameter.

It would just seem that rely of frameB keeps being placed w.r.t mainframe or root regardless of the root parameter I use for the instantiation of frameB or the said in_ parameter.

I know that I can use .pack(), but I am trying to figure out the behavior of .place() so please don't send me to use neither .pack() nor .grid().

What am I doing wrong? or (worse) miss-understanding ?

Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
epeleg
  • 10,347
  • 17
  • 101
  • 151
  • 1
    Because `frameA` is `None`, [since `place()` (and `pack()`, and `grid()`) returns `None`.](https://stackoverflow.com/questions/21592630/why-do-my-tkinter-widgets-get-stored-as-none) – CommonSense Oct 02 '17 at 10:54

1 Answers1

2

pack(), grid(), and place() return None, therefore, assigning frameA = Frame(bla bla).place(bla), is assigning None to frameA

You will need to do this in two steps to get what you need:

  • First create the widget.
  • Second place it.

Something along these lines:

mainFrame = Frame(parent, bd=5, bg="yellow")
mainFrame.pack(expand=True,fill=BOTH)

frameA = Frame(mainFrame, bd=5, bg="green")
frameA.place(anchor=NW, relx=0, rely=0 , relwidth=1.0, height=40)

my_label = Label(mainFrame, text="Hello world ", bg="red")
my_label.place(in_=frameA, relx=0, anchor=NW, rely=0, relwidth=0.5)

frameB = Frame(frameA, bd=5, bg="gold")
frameB.place(in_=frameA , anchor=N, relx=0.5, rely=0.8, width=30, height=50)
Reblochon Masque
  • 35,405
  • 10
  • 55
  • 80
  • Wonderful. That was exactly the problem. I wander why don't they return self instead... – epeleg Oct 02 '17 at 11:02
  • @epeleg, because `place` itself a method of `Place` class (same for `Grid` and `Pack`), so why it should return `self`? Anyway, it can return a widget (`self._w`), but is there a point for such behaviour, except of possibility to build a chain of function calls, in which desired widget returns twice in a row? – CommonSense Oct 02 '17 at 11:25
  • I would say that IMHO it makes sense to create a widget and pack/grid/place it in a single action (row of code) especially if the creation does not use many parameters And still want to have a reference to it for later use. maybe its because I come from other languages where this type of chaining is very commonly used. – epeleg Oct 03 '17 at 07:13
  • 1
    @epeleg, fair point. However, as you can see, Python doesn't share your passion from Java(JScript/JQuery) world, but.. proper chaining can be implemented in one way or another (implicitly or even [explicitly](https://stackoverflow.com/questions/39038358/function-chaining-in-python) for a personal needs), but I don't think that tradeoff is fair. Anyway, there's much info on the internet about it, so you're not alone! (; – CommonSense Oct 04 '17 at 08:09