simpleguy
simpleguy

Reputation: 283

tkinter - Run Function after Frame is Displayed

The code below has an onShowFrame function in the OtherPage class that runs when the OtherPage frame is shown. My problem is that everything in the onShowFrame function runs before the frame is actually displayed to the user. I've demonstrated this with time.sleep(5). What happens is the program sleeps for 5 seconds, remaining on BlankPage, before showing the OtherPage frame. I want the OtherPage frame to be shown first and then anything in the onShowFrame function to run.

How would I do this?

import tkinter as tk
import time

class Program(tk.Tk):        
    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)

        tk.Tk.iconbitmap(self, default = "")
        tk.Tk.wm_title(self, "")

        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 (BlankPage, OtherPage):

            frame = F(container, self)
            self.frames[F] = frame
            frame.grid(row = 0, column = 0, sticky = "nsew")

        self.showFrame(BlankPage)

    def showFrame(self,cont):
        frame = self.frames[cont]
        frame.tkraise()
        frame.event_generate("<<ShowFrame>>")

###########################################################################################################
class OtherPage(tk.Frame):
    def __init__(self, parent, controller):

        self.controller = controller
        tk.Frame.__init__(self, parent)

        innerFrame = tk.Frame(self)
        innerFrame.place(relx=.5, rely=.5, anchor="c", relwidth=1.0, relheight=1.0)

        innerFrame.grid_rowconfigure(0, weight=1)
        innerFrame.grid_columnconfigure(0, weight=1)

        self.frameOne = tk.Frame(innerFrame)
        self.frameOne.grid()

        label = tk.Label(self.frameOne, text = "Other Page")
        label.pack()

        self.bind("<<ShowFrame>>", self.onShowFrame)

    def onShowFrame(self, event):
        time.sleep(5)

###########################################################################################################

class BlankPage(tk.Frame):
    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)

        innerFrame = tk.Frame(self)
        innerFrame.place(relx=.5, rely=.5, anchor="c", relwidth=1.0, relheight=1.0)

        innerFrame.grid_rowconfigure(0, weight=1)
        innerFrame.grid_columnconfigure(0, weight=1)

        self.frameOne = tk.Frame(innerFrame)
        self.frameOne.grid()

        button = tk.Button(self.frameOne, text = "Press", command = lambda: controller.showFrame(OtherPage))
        button.pack()

app = Program()
app.state('zoomed')
app.mainloop()

Upvotes: 1

Views: 4035

Answers (1)

Bryan Oakley
Bryan Oakley

Reputation: 385980

The problem is related to the fact that you're calling sleep which causes the application to sleep. In order for the display to update, the event loop has to be able to process events, which it cannot do while sleeping. To sleep literally means to stop all processing. The first six words of the documentation for time.sleep is Suspend execution of the current thread.

This is one place where calling update on a widget is a reasonable thing to do. It will give tkinter a chance to process all pending events -- such as the finishing of handling a button click, redrawing the window, etc -- before generating the new event.

It's as easy as changing your function to look like this:

def showFrame(self,cont):
    frame = self.frames[cont]
    frame.tkraise()
    frame.update()
    frame.event_generate("<<ShowFrame>>")

Upvotes: 1

Related Questions