1

I am trying to make a GUI program which contain several pages with buttons and labels. I need the program to be able to dynamically change labels by pressing buttons to interact with labels on pages that I am not currently working at. I have made an example program that runs, but I get an error when trying to change labels in a page that is not being shown.

import tkinter as tk
from tkinter import ttk

LARGE_FONT = ("Verdana", 12)


class ManyPagesApp(tk.Tk):

    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)
        container = tk.Frame(self)
        container.pack(side="top", fill="both", expand=True)
        container.grid_rowconfigure(0, weight=1)
        container.grid_columnconfigure(0, weight=1)
        self.frames = {}

        # This loop adds the pages into the frame
        for F in (Page1, Page2):
            frame = F(container, self)
            self.frames[F] = frame
            frame.grid(row=0, column=0, sticky="nsew")
        self.show_frame(Page1)

    # This function raises the page to the "top" level of the frame
    def show_frame(self, cont):
        frame = self.frames[cont]
        frame.tkraise()


# Creates what shows in start page
class Page1(tk.Frame):

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

        button1 = ttk.Button(self, text="Go to Page 2", command=lambda: controller.show_frame(Page2))
        button1.pack()

        button2 = ttk.Button(self, text="THIS BUTTON CHANGES LABEL ON PAGE 1",
                         command=lambda: self.labelChanger('This label was changed by using button 2'))
        button2.pack()

        label = ttk.Label(self, text='This is Page 1', font=LARGE_FONT)
        label.pack(pady=10, padx=10)

        self.labelVariable1 = tk.StringVar()
        self.labelVariable1.set('This label will be changed')
        label = tk.Label(self, textvariable= self.labelVariable1)
        label.pack()

    def labelChanger(self, text):
        self.labelVariable1.set(text)

class Page2(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        objectofpage1 = Page1

        button1 = ttk.Button(self, text="Goes to page 1", command=lambda: controller.show_frame(Page1))
        button1.pack()

        button2 = ttk.Button(self, text="Changes Label 2 in page 1",
                         command=lambda: objectofpage1.labelChanger(objectofpage1, 'You have changed the label in page 1'))
        button2.pack()

        label = ttk.Label(self, text='This is page 2', font=LARGE_FONT)
        label.pack(pady=10, padx=10)



# Runs everything
if __name__ == "__main__":
    app = ManyPagesApp()
    app.mainloop()

My application got much bigger due to having more pages but I made this example program that gives me the same error.

OBS: The error only occurs when on page 2 and trying to change a label on page one.

And this is the error that pops up:

Exception in Tkinter callback
Traceback (most recent call last):
File "***\Python35-32\lib\tkinter\__init__.py", line 1549, in __call__
return self.func(*args)
  File "***/TestApp.py", line 63, in <lambda>
command=lambda: objectofpage1.labelChanger(objectofpage1, 'You have changed the label in page 1'))
  File "***/TestApp.py", line 51, in labelChanger
self.labelVariable1.set(text)
AttributeError: type object 'Page1' has no attribute 'labelVariable1'

PS: First time posting, I don't know if this is already been answered but I could not find anything to solve this problem so I made an account just to post this.

I appreciate the help a lot and thanks in advance!

  • 2
    `objectofpage1 = Page1`. You need to create an instance of `Page1`. The class `Page1` doesn't have a `labelVariable1` until it's been created, because it gets created in `__init__`. Note, this may not do what you what you think it does. – Morgan Thrapp Jul 15 '16 at 15:15
  • I had an indentation error when copying the code... the for loop should be indented. It should be a part of the __init__ inside the class ManyPagesApp... How do I edit the code I wrote there? – theBoringProgrammer Jul 15 '16 at 15:18
  • What should I do then? how do I make the variable labelVariable1 "global"? I know the error is there but I do not know what the solution is... – theBoringProgrammer Jul 15 '16 at 15:45

1 Answers1

2

The error is with this statement:

objectofpage1 = Page1

You are setting objectofpage1 to a class, not an instance of a class. Your program already has an instance, you just need to get the instance which is managed by the controller.

If each page needs access to the other pages, you simply need to add a method to the controller to return the instance. Something like this:

class ManyPagesApp(tk.Tk):
    ...
    def get_page(self, page_class):
        return self.frames[page_class]

class Page2(tk.Frame):

    def __init__(self, parent, controller):
        ...
        objectofpage1 = controller.get_page(Page1)

Note: you also have a bug in this statement:

command=lambda: objectofpage1.labelChanger(objectofpage1, 'You have changed the label in page 1'))

It should be:

command=lambda: objectofpage1.labelChanger('You have changed the label in page 1'))

For a more thorough discussion of sharing information between pages, see How to get variable data from a class

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