1

I'm new to python, hopefully can get some advise or right approach to solve this. I intended to create multiple frame in GUI, it works perfectly when i composed all classes in one python file, then I separated classes(Frame) into different file. Unfortunately, I could not link back to my MenuPage because of no reference in that particular python file(I tried to call MenuPage and it shows error after compile)... Maybe I was not familiar with the class call method... A main class created as below:

from tkinter import*
from GSOPage import*
class App(Tk):
    def __init__(self, *args, **kwargs):
        Tk.__init__(self, *args, **kwargs)

        container = 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, MenuPage, GSOPage):
            frame = F(container, self)
            self.frames[F] = frame
            frame.grid(row=0, column=0, sticky="nsew")
        self.show_frame(MenuPage)
    def show_frame(self, context):
        frame = self.frames[context]
        frame.tkraise()

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

class MenuPage(Frame):
    def __init__(self, parent, controller):
        Frame.__init__(self, parent)
        GSO = PhotoImage(file='GSOMenu.png')
        GSOM = Button(self, image=GSO, command=lambda: GSOAct())
        GSOM.image = GSO
        GSOM.place(x=-2,y=-2)
        def GSOAct():
            controller.show_frame(GSOPage)
...

Subclass : GSOPage

from tkinter import*
from GSOExp import*
class GSOPage(Frame):
   ...
    def __init__(self, parent, controller):
        Frame.__init__(self, parent)
        ...
        Back = PhotoImage(file="GSOBack.png")
        BackBtn = Button(self, image=Back, bd=0, bg='black', command=lambda: BackAct())
        BackBtn.image = Back
        BackBtn.place(x=0, y=0)
        def BackAct():
            controller.show_frame(MenuPage)

When I pressed BackBtn in GUI, it shows the error as below:

Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Users\Jun Hong\AppData\Local\Programs\Python\Python37-32\lib\tkinter\__init__.py", line 1705, in __call__
    return self.func(*args)
  File "C:\Users\Jun Hong\PycharmProjects\Tutorial\Calculator\GSOPage.py", line 18, in <lambda>
    BackBtn = Button(self, image=Back, bd=0, bg='black', command=lambda: BackAct())
  File "C:\Users\Jun Hong\PycharmProjects\Tutorial\Calculator\GSOPage.py", line 426, in BackAct
    controller.show_frame(MenuPage)
NameError: name 'MenuPage' is not defined

In conclusion, how can I link GSOPage back to MenuPage(defined in main class)

Thanks for help...

Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
Jun Hong
  • 35
  • 1
  • 3
  • That leads to circular imports, consider to use string `"MenuPage"` instead of `class MenuPage`. This requires to extend `controller.show_frame`. – stovfl Nov 18 '19 at 15:35

1 Answers1

0

Arguably the best solution is to not require you use the actual class. Instead, store the pages by class name. By doing so, you don't need to import every page into every other page.

For example, change the loop that makes the pages to look like this:

for F in (StartPage, MenuPage, GSOPage):
    page_name = F.__name__
    frame = F(parent=container, controller=self)
    self.frames[page_name] = frame
    frame.grid(row=0, column=0, sticky="nsew")

Next, modify show_page to accept a name rather than a class:

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

With that, from any file you can request a page with the name, and without having to import the page:

controller.show_frame("MenuPage")

Another solution would be to move the definition of Page to its own file, so that you don't have to import the main program in each of your pages.

That solution is described in a bit more detail here: Tkinter have code for pages in separate files

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