-1

Would anyone be able to explain why "hello" is being printed when the program is run? I was expecting only the welcome_frame to be run as that is the frame that has been raised, but that doesn't seem to be the case.

So why are all classes instantly run when I start the program, and how can I stop this from happening?

What I want is a button to be pressed within the welcome_frame which causes everything within the edit_booking_frame to be run.

Thank you :)

# import tkinter modules
from tkinter import *
from tkinter import ttk

# define self
class tkinterApp(Tk):

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

        # creating a container
        container = Frame(self)
        container.pack(side="top", fill="both", expand=True)

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

        # initialising frames to an empty array
        self.frames = {}

        for F in (welcome_frame, edit_booking_frame):
            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("welcome_frame")

    def show_frame(self, page_name):
        frame = self.frames[page_name]
        frame.tkraise()

class welcome_frame(Frame):
    def __init__(self, parent, controller):
        Frame.__init__(self, parent)
        self.controller = controller


class edit_booking_frame(Frame):
    def __init__(self, parent, controller):
        Frame.__init__(self, parent)
        self.controller = controller

        print("hello") ### WHY IS THIS PRINTED???


if __name__ == "__main__":
    app = tkinterApp()
    app.geometry("1000x800")
    app.mainloop()
  • In the for loop you have this line: `F(parent=container, controller=self)` and when `F` is `edit_booking_frame`, it calls `edit_booking_frame`'s constructor which is its `__init__` method. – TheLizzard Apr 10 '21 at 14:46
  • In the code you have all of the frames will be initialised but only the top frame is show on the screen. By calling `.tkraise()` in your `show_frame` method you make that frame the top one so the rest are bellow it. – TheLizzard Apr 10 '21 at 14:47

1 Answers1

0

So why are all classes instantly run when I start the program, and how can I stop this from happening?

That is simply what the code you copied is designed to do. Each class is instantiated at the very start of the program, in this loop:

for F in (welcome_frame, edit_booking_frame):
    page_name = F.__name__
    frame = F(parent=container, controller=self)
    self.frames[page_name] = frame

The line F(parent=container, controller=self) instantiates the class. The first time through the loop F is welcome_frame, the next time it is edit_booking_frame.

The loop is identical to doing this:

self.frames['welcome_frame'] = welcome_frame(parent=controller, controller_self)
self.frames['edit_booking_frame'] = edit_booking_frame(parent=controller, controller=self)

What I want is a button to be pressed within the welcome_frame which causes everything within the edit_booking_frame to be run.

If that is the case, probably shouldn't be using this code. This code was explicitly designed to create all of the frames upfront.

There are alternatives, and there are ways to arrange for code to be run once the frame has been shown. I recommend looking at all of the answers and links within the answer to this question:

Switch between two frames in tkinter

Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
  • Okay, I have looked through all the answers and links, and it seems that creating a custom event would be the best way of going about this...still not completely sure how to go about this. I've added a custom event to the `show_frame` function but not too sure where to go from there. Are custom events the best idea or am I just over-complicating things? I'm considering ditching classes completely TBH. – Benjamin McDowell Apr 10 '21 at 17:45