Home > OS >  Tkinter: Update variable in next frame
Tkinter: Update variable in next frame

Time:10-18

Good day StackOverFlow!

I need to update var in next frame, using tkinter after it's was changed. It's work, if i put code on "Page2" in function. BUT.

Can somebody advice please about this?

p.s. I apologize for the code not being clean enough.

import tkinter as tk
from tkinter import ttk
from tkinter import *

#Main frame

class tkinterApp(tk.Tk):
     
    # __init__ function for class tkinterApp
    def __init__(self, *args, **kwargs):

        # __init__ function for class Tk
        tk.Tk.__init__(self, *args, **kwargs)
         
        # creating a container
        container = tk.Frame(self) 
        self.geometry("450x350")
        self.title('tool')
        container.pack(side = "top", fill = "both", expand = True)
        container.grid_rowconfigure(0, weight = 1)
        container.grid_columnconfigure(0, weight = 1)
  
        # initializing frames to an empty array
        self.frames = {} 
  
        # iterating through a tuple consisting
        # of the different page layouts
        for F in (StartPage, 
                  Page2,):
            frame = F(container, self)
            self.frames[F] = frame
            frame.grid(row = 0, column = 0, sticky ="nsew")
        self.show_frame(StartPage)
  
    def show_frame(self, cont):
        frame = self.frames[cont]
        frame.tkraise()
#class

class Pages:
    global timeStamp
    timeStamp = 0

#start page

class StartPage(tk.Frame, Pages):

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

        def TimeFocusIn(event):
                timeStampInput.delete(0,"end")

        timeInputName = ttk.Label(self, 
                              text = "Enter Time in HHMMSS format:")
        timeStampInput = ttk.Entry(self)
        timeStampInput.insert(0, "HHMMSS")
        timeStampInput.bind("<FocusIn>", TimeFocusIn)

 #Save time button
        
        def SaveTime(**kwargs):
            global timeStamp
            var = StringVar()
            timeVarOut = timeStampInput.get()
            var.set(timeVarOut)
            timeVarOutTxt = ttk.Label(self, text=f'{timeVarOut}')
            timeVarOutTxt.grid(row = 7, column = 4, padx = 10, pady = 10)  
            timeStamp = timeVarOut

        saveTimeInputButt = ttk.Button(self, 
                                       text = "Save time", command = SaveTime)

        timeVarText = ttk.Label(self, 
                              text = "TimeStamp is:")
        
        buttPage2 = ttk.Button(self, text ="Next page",
                                  command = lambda : controller.show_frame(Page2))

#Grid placing

        timeInputName.grid(row = 5, column = 1, padx = 10, pady = 10, sticky ="nsew")
        timeStampInput.grid(row = 5, column = 2, padx = 10, pady = 10, sticky ="nsew")
        saveTimeInputButt.grid(row = 5, column = 4, padx = 10, pady = 10, sticky ="nsew")
        buttPage2.grid(row = 6, column = 1, padx = 10, pady = 10)
        timeVarText.grid(row = 7, column = 2, padx = 10, pady = 10)

#Page 2

class Page2(tk.Frame, Pages):
    def __init__(self, parent, controller):
        
        tk.Frame.__init__(self, parent)
        label = ttk.Label(self, text ="Next page")
        label.grid(row = 0, column = 4, padx = 10, pady = 10)
        timeVarOutTxt = ttk.Label(self, text=f'Timestamp is: {timeStamp}')
        timeVarOutTxt.grid(row = 1, column = 2, padx = 10, pady = 10)  

        button1 = ttk.Button(self, text ="Back",
                             command = lambda : controller.show_frame(StartPage))
        button1.grid(row = 1, column = 1, padx = 10, pady = 10)

# Run GUI

app = tkinterApp()

def message():
    app.update()
    print(timeStamp)
    app.after(20, message) 

app.after(20, message)
app.mainloop()

CodePudding user response:

If you want to share data between Frames then you could keep it in tkinterApp as self.timeStamp and then every page will have access using controller.timeStamp

if you want to access it in some function then keep self.controller = controller


But this can't change text in label - you have to do it on your own using

You have to use self. in self.timeVarOutTxt and later in saveTime you can access label in other frame and change it.

self.controller.frames[Page2].timeVarOutTxt['text'] = f'Timestamp is: {self.controller.timeStamp}'

Working code with other changes:

import tkinter as tk   # PEP8: `import *` is not preferred
from tkinter import ttk

# --- classes ---  # PEP8: all classes after imports

# Main frame  # PEP8: one space after `#` 

class tkinterApp(tk.Tk):
     
    # __init__ function for class tkinterApp
    def __init__(self, *args, **kwargs):

        # __init__ function for class Tk
        super().__init__(*args, **kwargs)
        
        #self.geometry("450x350")
        self.title('tool')

        self.time_stamp = 0
        
        # creating a container
        container = tk.Frame(self)
        container.pack(side="top", fill="both", expand=True)  # PEP8: inside `()` uses `=` without spaces
        container.grid_rowconfigure(0, weight=1)
        container.grid_columnconfigure(0, weight=1)
  
        # initializing frames to an empty array
        self.frames = {} 
  
        # iterating through a tuple consisting
        # of the different page layouts
        for F in (StartPage, Page2):
            frame = F(container, self)
            self.frames[F] = frame
            frame.grid(row=0, column=0, sticky="nsew")
            
        self.show_frame(StartPage)
  
    def show_frame(self, cont):
        frame = self.frames[cont]
        frame.tkraise()

class StartPage(tk.Frame):

    def __init__(self, parent, controller):
        super().__init__(parent)
        self.controller = controller

        time_input_name = ttk.Label(self, text="Enter Time in HHMMSS format:")
        
        self.time_stamp_input = ttk.Entry(self)
        self.time_stamp_input.insert(0, "HHMMSS")
        self.time_stamp_input.bind("<FocusIn>", self.time_focus_in)

        save_time_input_button = ttk.Button(self, text="Save time", command=self.save_time)

        time_var_text = ttk.Label(self, text="TimeStamp is:")
        
        button_page2 = ttk.Button(self, text="Next page", command=lambda:controller.show_frame(Page2))

        time_input_name.grid(row=5, column=1, padx=10, pady=10, sticky="nsew")
        self.time_stamp_input.grid(row=5, column=2, padx=10, pady=10, sticky="nsew")
        save_time_input_button.grid(row=5, column=4, padx=10, pady=10, sticky="nsew")
        button_page2.grid(row=6, column=1, padx=10, pady=10)
        time_var_text.grid(row=7, column=2, padx=10, pady=10)

    def time_focus_in(self, event):  # PEP8: `lower_case_names` for functions
        self.time_stamp_input.delete(0, "end")

    def save_time(self, **kwargs):  # PEP8: `lower_case_names` for functions  
        self.time_var_out_txt = ttk.Label(self, text=self.time_stamp_input.get())
        self.time_var_out_txt.grid(row=7, column=4, padx=10, pady=10)

        self.controller.time_stamp = self.time_stamp_input.get()
        self.controller.frames[Page2].time_var_out_txt['text'] = f'Timestamp is: {self.controller.time_stamp}'

class Page2(tk.Frame):
    def __init__(self, parent, controller):        
        super().__init__(parent)
        self.controller = controller
        
        label = ttk.Label(self, text="Next page")
        label.grid(row=0, column=4, padx=10, pady=10)
        
        self.time_var_out_txt = ttk.Label(self, text=f'Timestamp is: {controller.time_stamp}')
        self.time_var_out_txt.grid(row=1, column=2, padx=10, pady=10)  

        button1 = ttk.Button(self, text="Back", command=lambda:controller.show_frame(StartPage))
        button1.grid(row=1, column=1, padx=10, pady=10)

# --- functions ---  # PEP8: all functions after classes (before main code)

def message():
    #app.update()  # no need it
    print(app.time_stamp, end='\r')  # print in the same line
    app.after(20, message) 

# --- main ---

# Run GUI

app = tkinterApp()

app.after(20, message)

app.mainloop()

PEP 8 -- Style Guide for Python Code


EDIT:

Other idea: in every Page add function before_switch() and execute it

def show_frame(self, cont):
        frame = self.frames[cont]
        frame.before_switch()
        frame.tkraise()

and this function in class Page2 could update label always before displaying Page2

import tkinter as tk   # PEP8: `import *` is not preferred
from tkinter import ttk

# --- classes ---

# Main frame  # PEP8: one space after `#` 

class tkinterApp(tk.Tk):
     
    # __init__ function for class tkinterApp
    def __init__(self, *args, **kwargs):

        # __init__ function for class Tk
        super().__init__(*args, **kwargs)
        
        #self.geometry("450x350")
        self.title('tool')

        self.time_stamp = 0
        
        # creating a container
        container = tk.Frame(self)
        container.pack(side="top", fill="both", expand=True)  # PEP8: inside `()` uses `=` without spaces
        container.grid_rowconfigure(0, weight=1)
        container.grid_columnconfigure(0, weight=1)
  
        # initializing frames to an empty array
        self.frames = {} 
  
        # iterating through a tuple consisting
        # of the different page layouts
        for F in (StartPage, Page2):
            frame = F(container, self)
            self.frames[F] = frame
            frame.grid(row=0, column=0, sticky="nsew")
            
        self.frame = None
        self.show_frame(StartPage)
  
    def show_frame(self, cont):
        if self.frame:
            self.frame.after()
            
        self.frame = self.frames[cont]
        self.frame.before()
        
        self.frame.tkraise()

class Page(tk.Frame):

    def __init__(self, parent, controller):
        super().__init__(parent)
        self.controller = controller

    def before(self):
        """Run before showing Page."""
        pass
    
    def after(self):
        """Run after showing Page."""
        pass
    
class StartPage(Page):

    def __init__(self, parent, controller):
        super().__init__(parent, controller)

        time_input_name = ttk.Label(self, text="Enter Time in HHMMSS format:")
        
        self.time_stamp_input = ttk.Entry(self)
        self.time_stamp_input.insert(0, "HHMMSS")
        self.time_stamp_input.bind("<FocusIn>", self.time_focus_in)

        save_time_input_button = ttk.Button(self, text="Save time", command=self.save_time)

        time_var_text = ttk.Label(self, text="TimeStamp is:")
        
        button_page2 = ttk.Button(self, text="Next page", command=lambda:controller.show_frame(Page2))

        time_input_name.grid(row=5, column=1, padx=10, pady=10, sticky="nsew")
        self.time_stamp_input.grid(row=5, column=2, padx=10, pady=10, sticky="nsew")
        save_time_input_button.grid(row=5, column=4, padx=10, pady=10, sticky="nsew")
        button_page2.grid(row=6, column=1, padx=10, pady=10)
        time_var_text.grid(row=7, column=2, padx=10, pady=10)

    def time_focus_in(self, event):  # PEP8: `lower_case_names` for functions
        self.time_stamp_input.delete(0, "end")

    def save_time(self, **kwargs):  # PEP8: `lower_case_names` for functions  
        self.time_var_out_txt = ttk.Label(self, text=self.time_stamp_input.get())
        self.time_var_out_txt.grid(row=7, column=4, padx=10, pady=10)

    def after(self):
        """Update shared value after showing Page."""
        self.controller.time_stamp = self.time_stamp_input.get()

class Page2(Page):
    def __init__(self, parent, controller):        
        super().__init__(parent, controller)
        
        label = ttk.Label(self, text="Next page")
        label.grid(row=0, column=4, padx=10, pady=10)
        
        self.time_var_out_txt = ttk.Label(self, text=f'Timestamp is: {controller.time_stamp}')
        self.time_var_out_txt.grid(row=1, column=2, padx=10, pady=10)  

        button1 = ttk.Button(self, text="Back", command=lambda:controller.show_frame(StartPage))
        button1.grid(row=1, column=1, padx=10, pady=10)

    def before(self):
        """Update label before showing Page."""
        self.time_var_out_txt['text'] = f'Timestamp is: {self.controller.time_stamp}'

# --- functions ---

def message():
    #app.update()  # no need it
    print(app.time_stamp, end='\r')
    app.after(20, message) 

# --- main ---

# Run GUI

app = tkinterApp()

app.after(20, message)

app.mainloop()
  • Related