4

I have code that opens up a window and has three buttons for page 1, page 2, and page 3. However I also have four .py files (Dashboard, PageOne, PageTwo. PageThree). Dashboard will be the file that used to run the application. I want it so that the code from each file is only runs/displayed when the user clicks on the corresponding page button.

Dashboard.py:

import Tkinter as tk
import PageOne
import PageTwo
import PageThree

class Page(tk.Frame):
    def __init__(self, *args, **kwargs):
        tk.Frame.__init__(self, *args, **kwargs)
    def show(self):
        self.lift()

class MainView(tk.Frame):
    def __init__(self, *args, **kwargs):
        tk.Frame.__init__(self, *args, **kwargs)
        p1 = Page1(self)
        p2 = Page2(self)
        p3 = Page3(self)

        buttonframe = tk.Frame(self)
        container = tk.Frame(self)
        buttonframe.pack(side="top", fill="x", expand=False)
        container.pack(side="top", fill="both", expand=True)

        p1.place(in_=container, x=0, y=0, relwidth=1, relheight=1)
        p2.place(in_=container, x=0, y=0, relwidth=1, relheight=1)
        p3.place(in_=container, x=0, y=0, relwidth=1, relheight=1)

        b1 = tk.Button(buttonframe, text="Page 1", command=p1.lift)
        b2 = tk.Button(buttonframe, text="Page 2", command=p2.lift)
        b3 = tk.Button(buttonframe, text="Page 3", command=p3.lift)

        b1.pack(side="left")
        b2.pack(side="left")
        b3.pack(side="left")

        p1.show()

if __name__ == "__main__":
    root = tk.Tk()
    main = MainView(root)
    main.pack(side="top", fill="both", expand=True)
    root.wm_geometry("400x400")
    root.mainloop()

PageOne.py:

import Tkinter as tk
import Dashboard

class Page1(Page):
   def __init__(self, *args, **kwargs):
       Page.__init__(self, *args, **kwargs)
       label = tk.Label(self, text="This is page 1")
       label.pack(side="top", fill="both", expand=True)

PageTwo.py

import Tkinter as tk
import Dashboard

class Page2(Page):
   def __init__(self, *args, **kwargs):
       Page.__init__(self, *args, **kwargs)
       label = tk.Label(self, text="This is page 2")
       label.pack(side="top", fill="both", expand=True)

PageThree.py:

import Tkinter as tk
import Dashboard

class Page3(Page):
   def __init__(self, *args, **kwargs):
       Page.__init__(self, *args, **kwargs)
       label = tk.Label(self, text="This is page 3")
       label.pack(side="top", fill="both", expand=True)

Error I'm getting:

Traceback (most recent call last):
  File "C:\Users\ross.watson\Google Drive\Smart Mirror\Test\Dashboard.py", line 2, in <module>
    import PageOne
  File "C:\Users\ross.watson\Google Drive\Smart Mirror\Test\PageOne.py", line 2, in <module>
    import Dashboard
  File "C:\Users\ross.watson\Google Drive\Smart Mirror\Test\Dashboard.py", line 3, in <module>
    import PageTwo
  File "C:\Users\ross.watson\Google Drive\Smart Mirror\Test\PageTwo.py", line 4, in <module>
    class Page2(Page):
NameError: name 'Page' is not defined
martineau
  • 119,623
  • 25
  • 170
  • 301
Ross
  • 2,463
  • 5
  • 35
  • 91
  • 1
    Not 100% sure what you are getting at but is the answer as simple as placing each page inside a separate file (e.g. page1.py) and using 'from page1 import Page1' ? – scotty3785 Sep 16 '16 at 11:22
  • @scotty3785 When I cut `class Page3(Page):` in `PageThree.py` I get `NameError: global name 'Page1' is not defined` when running `Dashboard.py` – Ross Sep 16 '16 at 11:24
  • Might be helpful if you post what you have tried. How did you try to import the PageX class from its module? – scotty3785 Sep 16 '16 at 11:29
  • @scotty3785 I've edited my question, hopefully that makes it clearer what I'm trying to do. – Ross Sep 16 '16 at 11:35
  • What errors are you getting? – Dartmouth Sep 16 '16 at 11:40
  • 2
    Place the class Page in it's own file Page.py and use 'from Page import Page' in each of the PageX.py files. – scotty3785 Sep 16 '16 at 11:41
  • 1
    Also inside Dashboard.py you need to use p1 = PageOne.Page1(self) to initialise the page class. – scotty3785 Sep 16 '16 at 11:51
  • 1
    Also if you are trying to re-create a tabbed notebook effect, then you should probably just use the built in ttk.Notebook. The .lift method is designed to bring windows to the front not frame widgets – scotty3785 Sep 16 '16 at 11:53
  • @scotty3785 Thank you that worked. Ah I will look into ttk Notebook. Thanks again – Ross Sep 16 '16 at 11:54
  • `class page_1(give_me_some_subclass)` otherwise can't access `GUI`resource. Build with instantiation, don't call A in B or B in A. `From A import A` is wrong, `from a import *` suppressed all duplicate names – dsgdfg Sep 16 '16 at 11:55
  • @scotty3785: _" The .lift method is designed to bring windows to the front not frame widgets "_ is not a true statement. The `lift` command absolutely is designed to change the stacking order of _all_ widgets. However, your advice to use the ttk notebook is good. – Bryan Oakley Sep 16 '16 at 15:06
  • Ross: Why haven't you never accepted @Bryan's answer? – martineau Apr 11 '21 at 10:03

1 Answers1

6

The error messages tell you everything you need to know in order to fix the problem. This is a simple problem that has nothing to do with tkinter, and everything to do with properly organizing and using your code.

For example, what is Page is not defined telling you? It's telling you, quite literally, that Page is not defined. You defined it in your main file, but you're using it in another file. The solution is to move the definition of Page to a separate file that can be imported into the files that use it.

Modify your files and imports to look like this:

page.py

class Page(tk.Frame):
    ...

pageOne.py

from page import Page
class PageOne(Page):
    ...

pageTwo.py

from page import Page
class PageTwo(Page):
    ...

pageThree.py

from page import Page
class PageThree(Page):
    ...

Dashboard.py

from pageOne import PageOne
from pageTwo import PageTwo
from pageThree import PageThree
...
Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685