Getting correct values from variables in functions in Tkinter
Question: This is likely a simple problem related to how variables stored in a
dictionary are given values within a function.

I'm trying to get the value of a Boolean variable I'm storing in a dictionary
`(self.controller.Page1_data["Step1Complete"])` that I set to `"True"` in the
code below.

    
    
    #!/usr/local/bin/env python3
    import tkinter as tk   # python3
    from tkinter import BooleanVar
    
    TITLE_FONT = ("Helvetica", 18, "bold")
    
    class SampleApp(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.Page1_data={"Step1Complete": BooleanVar()}          
            self.frames = {}
            for F in (StartPage, PageFifteen): 
                page_name = F.__name__
                frame = F(container, self)
                self.frames[page_name] = frame
                frame.grid(row=0, column=0, sticky="nsew")          
            self.show_frame("StartPage")
    
        def show_frame(self, page_name):
            frame = self.frames[page_name]
            frame.tkraise()
    
    class StartPage(tk.Frame):
    
         def __init__(self, parent, controller):
            tk.Frame.__init__(self, parent)
            self.controller = controller
            controller.title("Part B Data Collection")
            controller.geometry("600x500")
            label = tk.Label(self, text="Welcome to the Part B Test!", font=TITLE_FONT)
            label.pack(side="top", fill="x", pady=10)
            button1 = tk.Button(self, text="Complete Step 1", command=self.MakeStep1Complete)
            button1.place(relx=0.385, rely=0.65)
    
        def MakeStep1Complete(self):
    
            Step1Complete=True
            self.controller.Page1_data["Step1Complete"]=Step1Complete
            self.controller.show_frame("PageFifteen")
    
    
    
    
    class PageFifteen(tk.Frame):
    
    
    
        def StatusCheck(self):
            Step1Complete=self.controller.Page1_data["Step1Complete"]
            print("True or false: at Step 15, Step 1 completed -a ")
            print(Step1Complete)
    
    
    
    
        def __init__(self, parent, controller):
            tk.Frame.__init__(self, parent)
            self.controller = controller
            label = tk.Label(self, text="Check the data", font=TITLE_FONT)
            label.pack(side="top", fill="x", pady=10)
    
            self.StatusCheck()
    
            tk.Label(self, text="Click on each of the buttons below to review the data you have inputted").place(relx=0.15, rely=0.12)  
    
            Step1Complete=self.controller.Page1_data["Step1Complete"].get()
            print("True or false: at Step 15, Step 1 completed - b")
            print(Step1Complete)
    
            button17=tk.Button(self, text="Check if we did everything", 
    
    command=self.StatusCheck)
            button17.place(relx=0.7, rely=0.75)        
    
        if __name__ == "__main__":
            app = SampleApp()
            app.mainloop()
    

When I execute the above (now edited per Florent's suggestions) code, I get
the following results:

    
    
    True or false: at Step 15, Step 1 completed -a 
    False
    True or false: at Step 15, Step 1 completed - b
    False
    True or false: at Step 15, Step 1 completed -a 
    True
    

The first result is from the first execution of the `StatusCheck` function,
where I simply call the function. The second result is from when I am
explicitly executing the command
`(Step1Complete=self.controller.Page1_data["Step1Complete"].get())` that ought
to (but doesn't) get the correct Boolean data. The third result, and the only
result that gets the correct Boolean data, is generated when the user clicks
the `"Check if we did everything"`, which calls the `StatusCheck` function
from the `tk.Button` command config option.

Why might this happen? Why would the `StatusCheck` function not work the first
time I execute it but then work the second time I execute it. Ideally, I'd
like the code to immediately find that the `"Step1Complete"` variable has been
set to `"True"` without having the user click a button.

I have reason to believe that the problem has something to do with which
functions write values to variables, since I'm able to make the program work
correctly when I set `"Step1Complete"` to `"True"` within the `__init__`
function in the `StartPage` class.

Being a Python N00b, I know I must be missing something pretty obvious, but I
really appreciate any help you could provide.


Answer: The short version of the answer is this: When you are using tkinter variables
you need to use set and get functions to access the value of the variables.
Also in an unrelated issue, in a class you don't need to define a function
before calling it and it is better to have __init__ on top of your class (cf
class PageFifteen).

Now, specifically for your code and why you get those prints: currently, you
call 2 prints when creating the PageFifteen Frame:

  * in the first on, you print a tk.BooleanVar, which gives you its handle and not its value (var.get() to print the value)
  * in the second one, you correctly use get() and print the current value of a your var (which is the default of a BooleanVar: False)

Then you show StartPage, click on button and you overwrite your Booleanvar
with the bool True, that's why your last StatusCheck works without a get.

In your code you need to replace:

    
    
    def StatusCheck(self):
        Step1Complete=self.controller.Page1_data["Step1Complete"]
        print("True or false: at Step 15, Step 1 completed -a ")
        print(Step1Complete)by
    

by:

    
    
    def StatusCheck(self):
        Step1Complete=self.controller.Page1_data["Step1Complete"].get()    
        print("True or false: at Step 15, Step 1 completed -a ")
        print(Step1Complete)
    

and

    
    
    def MakeStep1Complete(self):
        Step1Complete=True
        self.controller.Page1_data["Step1Complete"]=Step1Complete
        self.controller.show_frame("PageFifteen")
    

by:

    
    
    def MakeStep1Complete(self):
        Step1Complete=True
        self.controller.Page1_data["Step1Complete"].set(Step1Complete)
        self.controller.show_frame("PageFifteen")
    

