0

I have this code here and I want to pass values from one class (StartPage), to another (PageOne). I made a method in my controller "get_page" that let me access to page data among classes. So, I have an entry in StartPage and i want to pass its value to PageOne. So, the code runs, but in PageOne there is a print for debug. As soon as i start the program it automatically run all the code, almost like if PageOne is called even if I don't press the button. And the value I want to pass to the second page never gets passed. Can anyone help me out here please? Thanks in advance!

 import tkinter as tk                # python 3
 from tkinter import font as tkfont
 from typing_extensions import IntVar  # python 3

class SampleApp(tk.Tk):

def __init__(self, *args, **kwargs):
    tk.Tk.__init__(self, *args, **kwargs)

    self.title_font = tkfont.Font(family='Helvetica', size=18, weight="bold", slant="italic")

    # the container is where we'll stack a bunch of frames
    # on top of each other, then the one we want visible
    # will be raised above the others
    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 = {}
    for F in (StartPage, PageOne):
        page_name = F.__name__
        frame = F(parent=container, controller=self)
        self.frames[page_name] = frame

        # put all of the pages in the same location;
        # the one on the top of the stacking order
        # will be the one that is visible.
        frame.grid(row=0, column=0, sticky="nsew")

    self.show_frame("StartPage")

def show_frame(self, page_name):
    '''Show a frame for the given page name'''
    frame = self.frames[page_name]
    frame.tkraise()

def get_page(self, classname):
    '''Returns an instance of a page given it's class name as a string'''
    for page in self.frames.values():
        if str(page.__class__.__name__) == classname:
            return page
    return None


class StartPage(tk.Frame):

def __init__(self, parent, controller):
    tk.Frame.__init__(self, parent)
    self.controller = controller
    label = tk.Label(self, text="Start Page: insert value", font=controller.title_font)
    label.pack(side="top", fill="x", pady=10)

    self.some_input = tk.StringVar()
    self.some_entry = tk.Entry(self, width=8) 
    self.some_entry.pack()
    self.some_input = self.some_entry.get()
    button1 = tk.Button(self, text='Next Page', command=lambda: controller.show_frame("PageOne"))
    button1.pack()

class PageOne(tk.Frame):

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

    start_page = self.controller.get_page('StartPage')
    value = start_page.some_entry.get()
    print ('The value stored in StartPage entry = %s' % start_page.some_input)
    label = tk.Label(self, text="This is page 1, the value stored is" + str(value), font=controller.title_font)
    label.pack(side="top", fill="x", pady=10)
    button = tk.Button(self, text="Go to the start page",
                       command=lambda: controller.show_frame("StartPage"))
    button.pack()

if __name__ == "__main__":
app = SampleApp()
app.mainloop()
  • Look at your for loop: `for F in (StartPage, PageOne)` then `frame = F(parent=container, controller=self)`. That creates both `StartPage()` and `PageOne()` when the program is started. There are 2 possible solutions: create a function that the `StartPage` calls that creates the label inside `PageOne` or redesign your whole code. – TheLizzard Jul 06 '21 at 13:56
  • What do you mean by "a function tht start pages calls that creates the label inside page one?" – mandiatodos Jul 06 '21 at 14:51

1 Answers1

0

You need to find a way to notify PageOne to update the label whenever it is shown by show_frame(), one of the way is via virtual event using event_generate() function:

class SampleApp(tk.Tk):
    ...
    def show_frame(self, page_name):
        '''Show a frame for the given page name'''
        frame = self.frames[page_name]
        frame.tkraise()
        # notify frame that it is raised via virtual event
        frame.event_generate("<<Raised>>")

...
class PageOne(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        # save a reference of 'StartPage'
        self.start_page = self.controller.get_page('StartPage')
        # use instance variable 'self.label' instead of local variable 'label'
        self.label = tk.Label(self, font=controller.title_font)
        self.label.pack(side="top", fill="x", pady=10)
        button = tk.Button(self, text="Go to the start page",
                           command=lambda: controller.show_frame("StartPage"))
        button.pack()

        # bind the virtual event
        self.bind("<<Raised>>", self.on_raised)

    def on_raised(self, event):
        self.label.config(text=f"This is page 1, the value stored is '{self.start_page.some_entry.get()}'")
acw1668
  • 40,144
  • 5
  • 22
  • 34
  • thanks, this works, except for the fact that in "on raised" you have to use "self.start_page.some_input.get()". But I was thinking... wouldn't it be easier to just inherit start page in PageOne? – mandiatodos Jul 06 '21 at 14:22
  • No, it should be `self.start_page.some_entry.get()` because you have reassigned `some_input` to *an empty string* inside `StartPage.__init__()`: `self.some_input = self.some_entry.get()`. Inherit from `StartPage` is not a proper design. – acw1668 Jul 06 '21 at 14:29
  • But if I use `self.some_input` it works fine, if I use `self.some_entry` i get this error ` AttributeError: 'NoneType' object has no attribute 'get'` – mandiatodos Jul 06 '21 at 14:31
  • Then your posted code is not the same code you used. The code you used may be something like: `self.some_entry = tk.Entry(...).pack()`. – acw1668 Jul 06 '21 at 14:33
  • @mandiatodos Further to acw1668's comment, you code most likely has [this](https://stackoverflow.com/questions/1101750/tkinter-attributeerror-nonetype-object-has-no-attribute-attribute-name) mistake. – TheLizzard Jul 06 '21 at 14:57