Home > Back-end >  why this tkinter label updates on only one of three frames
why this tkinter label updates on only one of three frames

Time:10-02

This Tkinter app displays the same label across 3 frames, but is only updated on Frame3. why is Frame3 the active one when I start the app?

import tkinter as tk
from tkinter import ttk
import time


class RootContent(tk.Frame):
    """ 
    Define content of main window.
    """

    def __init__(self, parent):
        super(RootContent, self).__init__(parent)
        """
        The application is divided in pages, each page is a Frame(). The script starts by default 'raising' the page1.
        When click to change page, you call the raise_frame(frame_number) function to display a new page.
        """

        # all pages
        page1=tk.Frame()
        page2=tk.Frame()
        page3=tk.Frame()

        tk.Label(page1, text='PAGE 1', font='Verdana 20 bold').pack()
        tk.Label(page2, text='PAGE 2', font='Verdana 20 bold').pack()
        tk.Label(page3, text='PAGE 3', font='Verdana 20 bold').pack()

        # button page 1
        tk.Button(page1, text='page 2', command=lambda: raise_frame(page2)).pack(side='right')
        tk.Button(page1, text='page 3', command=lambda: raise_frame(page3)).pack(side='left')

        # buttons page 2
        tk.Button(page2, text='page 1', command=lambda: raise_frame(page1)).pack(side='left')
        tk.Button(page2, text='page 3', command=lambda: raise_frame(page3)).pack(side='right')

        # buttons page 3
        tk.Button(page3, text='page 2', command=lambda: raise_frame(page2)).pack(side='left')
        tk.Button(page3, text='page 1', command=lambda: raise_frame(page1)).pack(side='right')

        # function to update time being displayed
        def update_timelabel():
            time_actual = time.asctime()
            # timelabel.config(text=time_actual)
            timelabel['text']=time_actual
            timelabel.after(1000, update_timelabel)

        # function to change screen
        def raise_frame(frame):
            frame.tkraise()

        # define layout for all page frames inside root
        for frame in (page1, page2, page3):
            # horizontal line
            ttk.Separator(frame, orient='horizontal').pack(fill='x', anchor='s')

            # time label
            timelabel = tk.Label(frame, text='time info') # text to be modified
            timelabel.pack()

            # place frames in root
            frame.grid(row=0, column=0, sticky='news')

            # update time
            update_timelabel()
        
        # show page 1
        raise_frame(page1)


# call main loop
if __name__ == '__main__':
    # main window
    root = tk.Tk()
    root.resizable(0,0)
    root.geometry('400x200')
    main = RootContent(root)
    root.mainloop()

Is it a good idea to display a 'global label' that I only need to specify one time for as many frames as I have?

The original loop (for frames in (ALL 3 FRAMES): was made to expand the frame across the root window.

for frame in (page1, page2, page3):
    frame.grid(row=0, column=0, sticky='news')

And I used to add a widgets that will appear on all frames.

CodePudding user response:

The reason why it only works for frame 3 is because you reassigned the timelabel 3 times. The last time the timelabel updates its master is the last loop when it does something like this: tk.Label(page3, text='time info'). So how can you expect the timelabel works for all the frames? So I came up with a solution where timelabel is "kind of" stored 3 times. Basically you pass the timelabel you created as a parameter to the update_timelabel() function. This code below works for what you have asked:

import tkinter as tk
from tkinter import ttk
import time


class RootContent(tk.Frame):
    """ 
    Define content of main window.
    """

    def __init__(self, parent):
        super(RootContent, self).__init__(parent)
        """
        The application is divided in pages, each page is a Frame(). The script starts by default 'raising' the page1.
        When click to change page, you call the raise_frame(frame_number) function to display a new page.
        """

        # all pages
        page1=tk.Frame()
        page2=tk.Frame()
        page3=tk.Frame()

        tk.Label(page1, text='PAGE 1', font='Verdana 20 bold').pack()
        tk.Label(page2, text='PAGE 2', font='Verdana 20 bold').pack()
        tk.Label(page3, text='PAGE 3', font='Verdana 20 bold').pack()

        # button page 1
        tk.Button(page1, text='page 2', command=lambda: raise_frame(page2)).pack(side='right')
        tk.Button(page1, text='page 3', command=lambda: raise_frame(page3)).pack(side='left')

        # buttons page 2
        tk.Button(page2, text='page 1', command=lambda: raise_frame(page1)).pack(side='left')
        tk.Button(page2, text='page 3', command=lambda: raise_frame(page3)).pack(side='right')

        # buttons page 3
        tk.Button(page3, text='page 2', command=lambda: raise_frame(page2)).pack(side='left')
        tk.Button(page3, text='page 1', command=lambda: raise_frame(page1)).pack(side='right')

        # function to update time being displayed
        def update_timelabel(timelabel: tk.Label):
            time_actual = time.asctime()
            # timelabel.config(text=time_actual)
            timelabel['text']=time_actual
            timelabel.after(1000, lambda: update_timelabel(timelabel))

        # function to change screen
        def raise_frame(frame):
            frame.tkraise()

        # define layout for all page frames inside root
        for frame in (page1, page2, page3):
            # horizontal line
            ttk.Separator(frame, orient='horizontal').pack(fill='x', anchor='s')

            # time label
            timelabel = tk.Label(frame, text='time info') # text to be modified
            timelabel.pack()

            # place frames in root
            frame.grid(row=0, column=0, sticky='news')

            # update time
            update_timelabel(timelabel) # passing the label here as a parameter
        
        # show page 1
        raise_frame(page1)


# call main loop
if __name__ == '__main__':
    # main window
    root = tk.Tk()
    root.resizable(0,0)
    root.geometry('400x200')
    main = RootContent(root)
    root.mainloop()
  • Related