0

Using the methodology described in this post, I've created a multi-frame application. Without resizing the main window, the transitions from one frame to the next are very smooth, as all of the widgets are pre-loaded upon initializing the application.

However, many of my frames have different sizes, so ideally I would like to be able to set the geometry of the main window according to the requested size of the frame. I've used two methods thus far to achieve this, both working successfully:

  1. Using frame.grid_remove() on the top frame when switching to another, and then frame.grid() on the new top frame, as described in this post.
  2. Using the incoming frame's size attributes, frame.winfo_reqwidth() and frame.winfo_reqheight(), and then calling the master window's geometry(f'{width}x{height}') method to set the size.

However, my issue is that this transition, in both cases, is not smooth, and causes visual disruptions when switching frames, including leaving widgets blacked out until the mouse is moved again. I would like to make the resizing process less visually disruptive for my end-users.

import tkinter as tk, tkinter.ttk as ttk

class Application(tk.Tk):
    def __init__(self):
        super().__init__()
        container = tk.Frame(self)
        container.pack(side="top", fill="both", expand=True)
        container.grid_rowconfigure(0, weight=1)
        container.grid_columnconfigure(0, weight=1)

        self.frames = {}
        for F in (StartPage, PageOne, PageTwo):
            page_name = F.__name__
            frame = F(parent=container, controller=self)
            self.frames[page_name] = frame

            frame.grid(row=0, column=0, sticky="nsew")

        self.show_frame(StartPage)

    def show_frame(self, page_name):
        '''Show a frame for the given page name'''
        frame = self.frames[page_name]
        frame.tkraise()


class StartPage(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        label = tk.Label(self, text="This is the start page", font=controller.title_font)
        label.pack(side="top", fill="x", pady=10)

        button1 = tk.Button(self, text="Go to Page One",
                            command=lambda: controller.show_frame(PageOne))
        button2 = tk.Button(self, text="Go to Page Two",
                            command=lambda: controller.show_frame(PageTwo))
        button1.pack()
        button2.pack()


class PageOne(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        label = tk.Label(self, text="This is page 1", font=controller.title_font)
        label.pack(side="top", fill="x", pady=10)
        button = tk.Button(self, text="Go to the start page",
                           command=lambda: controller.show_frame(StartPage))
        button.pack()


class PageTwo(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        label = tk.Label(self, text="This is page 2", font=controller.title_font)
        label.pack(side="top", fill="x", pady=10)
        button = tk.Button(self, text="Go to the start page",
                           command=lambda: controller.show_frame(StartPage))
        button.pack()

The different versions of the Application method show_frame I have tried to use are:

1.

class Application(tk.Tk):
    def show_frame(self, page_name, frame_removed):
        frame = self.frames[page_name]
        frame_removed.grid_remove()
        frame.grid(sticky="nswe")

class StartPage(ttk.Frame):
    def __init__(self, parent, controller):
        ...
        button1 = ttk.Button(self, text="Go to page one", 
            command=lambda: controller.show_frame(PageOne, self))
        button2 = ttk.Button(self, text="Go to page two",
            command=lambda: controller.show_frame(PageTwo, self))

# all pages have been modified in the same manner as this
class Application(tk.Tk):
    def show_frame(self, page_name):
        frame = self.frames[page_name]
        width = str(frame.winfo_reqwidth())
        height = str(frame.winfo_reqheight())
        if width != "1":
            self.geometry(f'{width}x{height}')
        frame.tkraise()
jthree8
  • 81
  • 8
  • We can't debug code which we can't see. Please [edit] your question to include a [mcve]. – Bryan Oakley Nov 06 '20 at 05:02
  • *"leaving widgets blacked out until the mouse is moved again"* I think this is related to your system or installed tk library, not on the way how to resize the frame. Your attempt 1 works fine in my Python 3.8.6 under Windows 7. – acw1668 Nov 06 '20 at 06:08
  • I am on macOS Catalina 10.15.7 with Python 3.8.2, I believe using Tk version 8.5 - however, I'm using the system-provided version of Python 3, should I go through the trouble of installing Python 3.9 and using virtual environments to develop? – jthree8 Nov 06 '20 at 20:34

0 Answers0