-1

I'm new to python and trying to make a GUI with tkinter for a study application. I'm having trouble setting up my program to be able to navigate to different pages. I used this stack overflow question to set up my code.

Using buttons in Tkinter to navigate to different pages of the application?

the problem with this particular solution is that it creates buttons at the top of the parent window that allow the user to navigate to each page in the program. It wouldn't make sense in my program to allow the user to navigate to any page at any time. How would I create a button on a specific page that allows me to navigate to a different page?

study_button() is my attempt at this

from tkinter import *

#initializes each page as a class
class Page(Frame):
    def __init__(self, *args, **kwargs):
        Frame.__init__(self, *args, **kwargs)
    def show(self):
        self.lift()

#creates a specific page
class SelectionPage(Page):
    def __init__(self, *args, **kwargs):
        Page.__init__(self, *args, **kwargs)
        label = Label(self, text='selection page')
        label.pack()

        def study_button():
            studypage = StudyPage(self)
            studypage.lift()

            print("study")

        studybutton = Button(self, text = "Study", command=study_button)
        studybutton.pack()


class StudyPage(Page):
    def __init__(self, *args, **kwargs):
        Page.__init__(self, *args, **kwargs)
        label = Label(self, text = 'this is the study page')
        label.pack()

class ModifyPage(Page):
    def __init__(self, *args, **kwargs):
        Page.__init__(self, *args, **kwargs)
        label = Label(self, text = 'this is the modify page')
        label.pack()
#base page
class MainView(Frame):
    def __init__(self, *args, **kwargs):
        Frame.__init__(self, *args, **kwargs)

        studypage = StudyPage(self)
        selectionpage = SelectionPage(self)
        modifypage = ModifyPage(self)

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

        studypage.place(in_=container, x=0, y=0, relwidth=1, relheight=1)
        selectionpage.place(in_=container, x=0, y=0, relwidth=1, relheight=1)
        modifypage.place(in_=container, x=0, y=0, relwidth=1, relheight=1)

        selectionpage.show()



if __name__ == "__main__":
    root = Tk()
    main = MainView(root)
    main.pack(side="top", fill="both", expand=True)
    root.wm_geometry("400x400")
    root.mainloop()
  • Your question is unclear. There are many ways to put buttons on each page, there's nothing unique that needs to be done. Add the button like you would any other button. – Bryan Oakley Jan 11 '20 at 21:33
  • Asterisk imports are a bad idea. – AMC Jan 11 '20 at 22:27
  • @Bryan Oakley In regards to that thread I linked, I've been tinkering with the code you wrote for hours trying to figure it out. What I don't understand is that when you create a class for a page in tkinter, do you ever create an instance of that page? I've been trying to print the instance to get a better idea of what obects i'm dealing with but I don't know how to call them – coding_guy69 Jan 14 '20 at 16:02
  • ***"when you create a class for a page, do you ever create an instance of that page?"***: This **defines** a page object: `class StudyPage(Page):` and this **creates a instance**: `studypage = StudyPage(self)`. The reference of the instance get assigned to `studypage`. – stovfl Jan 15 '20 at 16:20

1 Answers1

0

Here's how to apply the pattern shown in one of @Bryan Oakley's many other tkinter-related answers to your code. It adds a pages dictionary attribute to the MainView class which can be used in the Page subclasses to reference any of the instance of the others by their class name.

To facilitate that, a named controller argument has been added to the calling sequence of each subclass. This will be the instance of MainView controlling them.

Note I also added a Button to your StudyPage that goes to the ModifyPage to give you a better idea of the pattern.

from tkinter import *


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

    def show(self):
        self.lift()


class SelectionPage(Page):
    def __init__(self, controller, *args, **kwargs):
        Page.__init__(self, *args, **kwargs)
        label = Label(self, text='Selection page')
        label.pack()

        def study_button():
            studypage = controller.pages['StudyPage']
            studypage.show()
            print("study")

        studybutton = Button(self, text="Study", command=study_button)
        studybutton.pack()


class StudyPage(Page):
    def __init__(self, controller, *args, **kwargs):
        Page.__init__(self, *args, **kwargs)
        label = Label(self, text='This is the study page')
        label.pack()

        def modify_button():
            modifypage = controller.pages['ModifyPage']
            modifypage.show()
            print("modifying")

        modifybutton = Button(self, text="Modify", command=modify_button)
        modifybutton.pack()


class ModifyPage(Page):
    def __init__(self, controller, *args, **kwargs):
        Page.__init__(self, *args, **kwargs)
        label = Label(self, text='This is the modify page')
        label.pack()


class MainView(Frame):
    def __init__(self, *args, **kwargs):
        Frame.__init__(self, *args, **kwargs)

        # Create dictionary of Page subclasses.
        self.pages = {}
        for Subclass in (StudyPage, SelectionPage, ModifyPage):
            self.pages[Subclass.__name__] = Subclass(self)

        studypage, selectionpage, modifypage = self.pages.values()

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

        studypage.place(in_=container, x=0, y=0, relwidth=1, relheight=1)
        selectionpage.place(in_=container, x=0, y=0, relwidth=1, relheight=1)
        modifypage.place(in_=container, x=0, y=0, relwidth=1, relheight=1)

        selectionpage.show()



if __name__ == "__main__":
    root = Tk()
    main = MainView(root)
    main.pack(side="top", fill="both", expand=True)
    root.wm_geometry("400x400")
    root.mainloop()
martineau
  • 119,623
  • 25
  • 170
  • 301
  • can you explain to me why you used a dictionary to store the names of the subclasses? would it not be easier to just use a list? I'm new to python and just trying to make sense of this – coding_guy69 Jan 12 '20 at 19:00
  • I used a dictionary to provide an easy and readable way to select the desired page subclass, avoid magic numbers, as well as dependencies on the order they are created and added. I've also seen it done by using the subclasses' themselves as the indice, but that's very uncommon and has its own potential drawbacks. – martineau Jan 12 '20 at 19:50