0

Ive been playing around with a Page Switching example from here: Switch between two frames in tkinter

Im trying to use the "place()" layout manager to sort widgets on the page but whenever I use it, they simply don't appear on the page. It's important I use it over pack and grid for the program I want to create, how can I make them work?

For example, in the following code, "Welcome" doesn't show up on the "StartTest" page.

import tkinter as tk
import random

title_font=("Microsoft Jhenghei UI Light", 35)

class MathsApp(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)
        self._frame = None
        self.switch_frame(StartTest)
        self.title("Maths Revision App")
        self.geometry("800x500")
        self.configure(bg="white")

    def switch_frame(self, frame_class):
        """Destroys current frame and replaces it with a new one."""
        new_frame = frame_class(self)
        if self._frame is not None:
            self._frame.destroy()
        self._frame = new_frame
        self._frame.pack()

class StartTest(tk.Frame):
    def __init__(self, master):
        tk.Frame.__init__(self, master)
        #welcome label
        tk.Label(self, text="Welcome!", font=title_font, bg="white", fg="#004d99").place(x=30, y=20)
        tk.Button(self, text="Open page one",
              command=lambda: master.switch_frame(PageOne)).pack()
        tk.Button(self, text="Open page two",
              command=lambda: master.switch_frame(PageTwo)).pack()

class PageOne(tk.Frame):
    def __init__(self, master):
        tk.Frame.__init__(self, master)
        tk.Label(self, text="This is page one").pack(side="top", fill="x", pady=10)
        tk.Button(self, text="Return to start page",
              command=lambda: master.switch_frame(StartTest)).pack()

class PageTwo(tk.Frame):
    def __init__(self, master):
        tk.Frame.__init__(self, master)
        tk.Label(self, text="This is page two").pack(side="top", fill="x", pady=10)
        tk.Button(self, text="Return to start page",
              command=lambda: master.switch_frame(StartTest)).pack()

if __name__ == "__main__":
    app = MathsApp()
    app.mainloop()

I tried removing the other buttons on the page, but the "Welcome" Label still didn't show up.

Tolu
  • 3
  • 2
  • Without **Layout** using `pack` or `grid` they never show up. – stovfl Feb 10 '19 at 18:36
  • Would that mean I can't use place? Only pack or grid would work for this? – Tolu Feb 10 '19 at 18:50
  • Overlooked your `.place(x=30, y=20)` at the end. But, using `place` on a **NOT** fixed sized `Frame` will have no effect. **Second**, using **two** different `Geometry Manager` complicating things. If you look with sharp eyes, you will see the `Welcom` at right side of `Page Two`. Read [When to use the Place Manager](http://effbot.org/tkinterbook/place.htm) – stovfl Feb 10 '19 at 19:27
  • 1
    @stovfl: I don't think it's correct to say using place on a not-fixed-size frame will have no effect. It will definitely have an effect, it just may not be visible, depending on the options. – Bryan Oakley Feb 10 '19 at 19:33
  • @Bryan: The following `pack` sizes the `Frame` to the size of the two `Button`, therefore **no visual effect**. @Tolu: Expand your `Frame` using `self._frame.pack(fill=tk.BOTH, expand=True)` – stovfl Feb 10 '19 at 19:42
  • 1
    @stovfl: yes, like I said there may be no visible effect, but there is definitely an effect. The label is definitely there and definitely on the screen. It's just that other widgets are obscuring it. – Bryan Oakley Feb 10 '19 at 19:56

1 Answers1

0

Your use of place is the root of the problem, but the real problem is a combination of three choices you've made:

  1. you are using pack on the buttons in StartTest but not on the label,
  2. when you add StartTest to the root window, you aren't telling it to fill the window,
  3. you create the "Welcome" label before you create the buttons, causing it to appear behind the buttons.

The net effect is that StartTest is only just big enough to fit the buttons, and the buttons are on top of the label. The label is there, but because of all of the other choices you've made, it's hard to see it.

This can be illustrated by moving the welcome label on top of the buttons. Change your __init__ so that it creates the label last:

class StartTest(tk.Frame):
    def __init__(self, master):
        tk.Frame.__init__(self, master, background="bisque")
        tk.Button(self, text="Open page one",
              command=lambda: master.switch_frame(PageOne)).pack()
        tk.Button(self, text="Open page two",
              command=lambda: master.switch_frame(PageTwo)).pack()
        tk.Label(self, text="Welcome!, blah blah blah blah", font=title_font, bg="white", fg="#004d99").place(x=30, y=20)

This is what your window will look like (I've reduced the window size to 300x200 to keep the image small):

enter image description here

The next part of the problem is that the frames don't fill the window. This can be easily illustrated by giving your StartTest a unique color so that it stands out.

Change the __init__ function to start like this (notice the use of the color "red" in the third line):

class StartTest(tk.Frame):
    def __init__(self, master):
        tk.Frame.__init__(self, master, background="red")
        ...

When you run it, notice that there is no red anywhere on the screen. That's a hint that we can't see the frame. In this case that's because it has shrunk to fit the buttons, and the other options cause the buttons to completely fill the background (ie: there's no padding which will allow the background to show through).

To solve this, you need to change how you're calling pack inside show_frame. You need to make sure that the frame completely fills the window. Do that by changing the pack command to look like this:

self._frame.pack(fill="both", expand=True)

With all of those changes together, the window now looks like this:

enter image description here

As you can see, the inner frame now fills the window, and the full label is visible. I doubt it's in the place you expect, but at least now you can see it and hopefully better understand why you couldn't see it before.

Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685