Zachary Berkowitz
Zachary Berkowitz

Reputation: 17

Tkinter: How to show pages with buttons on page?

I'm writing a "hotline" program for a bullying/abuse project, with 4 pages: Home/Bulling/Abuse/Other and a top bar. I am putting buttons to get to the other pages, but there is a different error every time.

I have tried the lift command from the page and the container, as well as the show command programmed in. Neither work. (By the way, the code is not all mine, much of it was from the question Using buttons in Tkinter to navigate to different pages of the application? by Caspar Wylie)

import tkinter as tk

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

class Page1(Page):
   def __init__(self, *args, **kwargs):
       Page.__init__(self, *args, **kwargs)
       label = tk.Label(self, text="Welcome to the Help Hotline! Please select your concern.", relief = 'groove')
       label.grid(row = 0, column = 1, columnspan = 3, sticky = 'nesw', padx = 5, pady = 5)

       bullybutton = tk.Button(self, text = "Bullying",  command = MainView.p2.lift)
       bullybutton.grid(row = 1, column = 1, padx = 5, pady = 5, sticky = 'nsew')

       abusebutton = tk.Button(self, text = "Abuse",  command = MainView.p3.lift)
       abusebutton.grid(row = 1, column = 2, padx = 5, pady = 5, sticky = 'nsew')

       otherbutton = tk.Button(self, text = "Other",  command = MainView.p4.lift)
       otherbutton.grid(row = 1, column = 3, padx = 5, pady = 5, sticky = 'nsew')

class Page2(Page):
   def __init__(self, *args, **kwargs):
       Page.__init__(self, *args, **kwargs)
       label = tk.Label(self, text="This is page 2")
       label.grid(row = 0, column = 1, sticky = 'nesw', padx = 5, pady = 5)

class Page3(Page):
   def __init__(self, *args, **kwargs):
       Page.__init__(self, *args, **kwargs)
       label = tk.Label(self, text="This is page 3")
       label.grid(row = 0, column = 1, sticky = 'nesw', padx = 5, pady = 5)

class Page4(Page):
   def __init__(self, *args, **kwargs):
       Page.__init__(self, *args, **kwargs)
       label = tk.Label(self, text="This is page 4")
       label.grid(row = 0, column = 1, sticky = 'nesw', padx = 5, pady = 5)

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

        container = tk.Frame(self)
        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)
        p4.place(in_=container, x=0, y=0, relwidth=1, relheight=1)

        menubar = tk.Menu(root)
        filemenu = tk.Menu(menubar, tearoff=0)
        filemenu.add_command(label="Home", command=p1.lift)
        filemenu.add_command(label="Bullying", command=p2.lift)
        filemenu.add_command(label="Abuse", command=p3.lift)
        filemenu.add_command(label="Other", command=p4.lift)
        filemenu.add_separator()
        filemenu.add_command(label="Quit", command=exit)
        menubar.add_cascade(label="Navigate", menu=filemenu)

        root.config(menu=menubar)
        p1.show()


root = tk.Tk()
root.geometry('500x500')
main = MainView(root)
main.pack(side="top", fill="both", expand=True)
root.title("Bullying and Abuse Hotline")
root.mainloop()

I want there to be 3 buttons, each going to their own page, but I get an error about "no attribute tk" or "missing argument self" or no change at all.

Upvotes: 0

Views: 189

Answers (1)

martineau
martineau

Reputation: 123531

Here's a (fairly major) reworking of your code that I think makes it do what you want. You didn't provide a link to Caspar Wylie's question, so I've borrowed heavily on the techniques shown in Bryan Oakley's seminal answer to the question Switch between two frames in tkinter that does very similar things although doesn't feature a menu (but does contain a number of possibly very useful links at the end).

Update

Found Caspar Wylie's question myself and added link to it in your question and have modified the code below slightly to be more consistent to the associated answer (which happens to also have been written by Bryan).

import tkinter as tk


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

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

        # Create dictionary of page (Frame subclass) instances.
        self.pages  = {}
        for Page in (Home, Bullying, Abuse, Other):
            page = Page(container, controller=self)
            self.pages[Page.__name__] = page
            page.place(in_=container, x=0, y=0, relwidth=1, relheight=1)

        menubar = tk.Menu(parent)
        filemenu = tk.Menu(menubar, tearoff=0)

        def options(page_name, show=self.show):  # Helper func.
            return dict(label=page_name, command=lambda: show(page_name))

        filemenu.add_command(**options('Home'))
        filemenu.add_command(**options('Bullying'))
        filemenu.add_command(**options('Abuse'))
        filemenu.add_command(**options('Other'))

        filemenu.add_separator()
        filemenu.add_command(label='Quit', command=exit)
        menubar.add_cascade(label='Navigate', menu=filemenu)

        parent.config(menu=menubar)
        self.show('Home')  # Display initial page.

    def show(self, page_name):
        self.pages[page_name].lift()


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

       label = tk.Label(self, text='Welcome to the Help Hotline! '
                                   'Please select your concern.', relief='groove')
       label.grid(row=0, column=1, columnspan=3, sticky='nesw', padx=5, pady=5)

       def options(page_name, show=controller.show):  # Helper func.
           return dict(text=page_name, command=lambda: show(page_name))

       bully_button = tk.Button(self, **options('Bullying'))
       bully_button.grid(row = 1, column=1, padx=5, pady=5, sticky='nsew')

       abuse_button = tk.Button(self, **options('Abuse'))
       abuse_button.grid(row=1, column=2, padx=5, pady=5, sticky='nsew')

       other_button = tk.Button(self, **options('Other'))
       other_button.grid(row=1, column=3, padx=5, pady=5, sticky='nsew')


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

       label = tk.Label(self, text='This is page 2')
       label.grid(row=0, column=1, sticky='nesw', padx=5, pady=5)


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

       label = tk.Label(self, text='This is page 3')
       label.grid(row=0, column=1, sticky='nesw', padx=5, pady=5)


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

       label = tk.Label(self, text='This is page 4')
       label.grid(row=0, column=1, sticky='nesw', padx=5, pady=5)


root = tk.Tk()
root.geometry('500x500')
main = MainView(root)
main.pack(side='top', fill='both', expand=True)
root.title('Bullying and Abuse Hotline')
root.mainloop()

Upvotes: 1

Related Questions