Patterns

Let's look at some usage patterns. The following command centers a widget in its parent:

    w.place(relx=0.5, rely=0.5, anchor=CENTER)

Here's another variant. It packs a Label widget in a frame widget, and then places a Button in the upper right corner of the frame. The button will overlap the label.

    pane = Frame(master)
    Label(pane, text="Pane Title").pack()
    b = Button(pane, width=12, height=12,
               image=launch_icon, command=self.launch)
    b.place(relx=1, x=-2, y=2, anchor=NE)

The following excerpt from a Notepad widget implementation displays a notepad page (implemented as a Frame) in the notepad body frame. It first loops over the available pages, calling place_forget for each one of them. Note that it's not an error to "unplace" a widget that it's not placed in the first case:

    for w in self.__pages:
        w.place_forget()
    self.__pages[index].place(in_=self.__body, x=bd, y=bd)

You can combine the absolute and relative options. In such cases, the relative option is applied first, and the absolute value is then added to that position. In the following example, the widget w is almost completely covers its parent, except for a 5 pixel border around the widget.

    w.place(x=5, y=5, relwidth=1, relheight=1, width=-10, height=-10)

You can also place a widget outside another widget. For example, why not place two widgets on top of each other:

    w2.place(in_=w1, relx=0.5, y=-2, anchor=S, bordermode="outside")

Note the use of relx and anchor options to center the widgets vertically. You could also use (relx=0, anchor=SW) to get left alignment, or (relx=1, anchor=SE) to get right alignment.

By the way, why not combine this way to use the packer with the launch button example shown earlier. The following example places two buttons in the upper right corner of the pane:

    b1 = DrawnButton(pane, (12, 12), launch_icon, command=self.launch)
    b1.place(relx=1, x=-2, y=2, anchor=NE)
    b2 = DrawnButton(pane, (12, 12), info_icon, command=self.info)
    b2.place(in_=b1, x=-2, anchor=NE, bordermode="outside")

Finally, let's look at a piece of code from an imaginary SplitWindow container widget. The following piece of code splits frame into two subframes called f1 and f2.

    f1 = Frame(frame, bd=1, relief=SUNKEN)
    f2 = Frame(frame, bd=1, relief=SUNKEN)
    split = 0.5
    f1.place(rely=0, relheight=split, relwidth=1)
    f2.place(rely=split, relheight=1.0-split, relwidth=1)

To change the split point, set split to something suitable, and call the place method again. If you haven't changed an option, you don't have to specify it again.

    f1.place(relheight=split)
    f2.place(rely=split, relheight=1.0-split)

You could add a small frame to use as a dragging handle, and add suitable bindings to it, e.g:

    f3 = Frame(frame, bd=2, relief=RAISED, width=8, height=8)
    f3.place(relx=0.9, rely=split, anchor=E)
    f3.bind("<B1-Motion>", self.adjust)