0

I have this code which display a page and then when press PAGE1 button go to other frame. Here i want to display time in any of the labels but i want it update automatically. I couldn t manage do it myself

import Tkinter as tk
from Tkinter import *
import time
import datetime

def clock():
    time = datetime.datetime.now().strftime("Time: %H:%M:%S")
    print time

class MainApp(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 = {}
        for F in (MainPage, page1, help):
            page_name = F.__name__
            frame = F(parent=container, controller=self)
            self.frames[page_name] = frame
            frame.grid(row=0, column=0, columnspan=12,sticky="nsew")
            frame.grid_columnconfigure(0, weight=1)
            frame.grid_columnconfigure(1, weight=1)
            frame.grid_columnconfigure(2, weight=1)
            frame.grid_columnconfigure(3, weight=1)
            frame.grid_columnconfigure(4, weight=1)
            frame.grid_columnconfigure(5, weight=1)
            frame.grid_columnconfigure(6, weight=1)
            frame.grid_columnconfigure(7, weight=1)
            frame.grid_columnconfigure(8, weight=1)
            frame.grid_columnconfigure(9, weight=1)
            frame.grid_columnconfigure(10, weight=1)
            frame.grid_columnconfigure(11, weight=1)

        self.show_frame("MainPage")
        clock()
    def show_frame(self, page_name):
        frame = self.frames[page_name]
        frame.tkraise()


class MainPage(tk.Frame):

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

        # line 0
        label00 = tk.Label(self, text='00', height=2)
        label00.configure(relief='raised')
        label00.grid(row=0, column=0, sticky='nsew', columnspan=12)
        # line 1
        label10 = tk.Label(self, text='10')
        label10.configure(relief='raised')
        label10.grid(row=1, column=0, sticky='nsew')
        label11 = tk.Label(self, text='LOGO')
        label11.configure(relief='raised')
        label11.grid(row=1, column=1, sticky='nsew', columnspan=4, rowspan=2)
        label12 = tk.Label(self, text='12')
        label12.configure(relief='raised')
        label12.grid(row=1, column=5, sticky='nsew')
        label13 = tk.Label(self, text='TITLE')
        label13.configure(relief='raised')
        label13.grid(row=1, column=6, sticky='nsew', columnspan=5)
        label14 = tk.Label(self, text='14')
        label14.configure(relief='raised')
        label14.grid(row=1, column=11, sticky='nsew')
        # line 2
        label20 = tk.Label(self, text='20')
        label20.configure(relief='raised')
        label20.grid(row=2, column=0, sticky='nsew')
        label21 = tk.Label(self, text='21')
        label21.configure(relief='raised')
        label21.grid(row=2, column=5, sticky='nsew')
        label22 = tk.Label(self, text='Desc')
        label22.configure(relief='raised')
        label22.grid(row=2, column=6, sticky='nsew', columnspan=5)
        label23 = tk.Label(self, text='23')
        label23.configure(relief='raised')
        label23.grid(row=2, column=11, sticky='nsew')
        # line 3
        label30 = tk.Label(self, text='30', height=2)
        label30.configure(relief='raised')
        label30.grid(row=3, column=0, sticky='nsew', columnspan=12)
        #line 4
        label40 = tk.Label(self, text='40', width=10)
        label40.configure(relief='raised')
        label40.grid(row=4, column=0, sticky='nsew')
        label41 = tk.Label(self, text='STATUS', font=("Helvetica", 16), justify='center', fg="blue")
        label41.configure(relief='raised')
        label41.grid(row=4, column=1, columnspan=10)
        label42 = tk.Label(self, text='42', width=10)
        label42.configure(relief='raised')
        label42.grid(row=4, column=11, sticky='nsew')
        #line 5
        label50 = tk.Label(self, text='50', height=2)
        label50.configure(relief='raised')
        label50.grid(row=5, column=0, columnspan=12, sticky="nsew")
        #line 6
        label60 = tk.Label(self, text='60', height=2)
        label60.configure(relief='raised')
        label60.grid(row=6, column=0, sticky='nsew')
        buttonauto = tk.Button(self, text="PAGE1", font=("Helvetica", 16), justify='center', width=40, height=5,
                              command=lambda: controller.show_frame("page1"))
        buttonauto.grid(row=6, column=1, columnspan=4)
        label61 = tk.Label(self, text='61', height=2)
        label61.configure(relief='raised')
        label61.grid(row=6, column=5, sticky='nsew')
        label62 = tk.Label(self, text='62', height=2)
        label62.configure(relief='raised')
        label62.grid(row=6, column=6, sticky='nsew')
        buttoncam = tk.Button(self, text="HELP",font=("Helvetica", 16), justify='center', width=40, height=5,
                              command=lambda: controller.show_frame("help"))
        buttoncam.grid(row=6 , column=7, columnspan=4)
        label63 = tk.Label(self, text='63', height=2)
        label63.configure(relief='raised')
        label63.grid(row=6, column=11, sticky='nsew')
        # line 7
        label70 = tk.Label(self, text='70', height=2)
        label70.configure(relief='raised')
        label70.grid(row=7, column=0, sticky='nsew', columnspan=12)

        #line 13
        label13 = tk.Label(self, text='', height=2)
        label13.configure(relief='raised')
        label13.grid(row=13, column=0, columnspan=12, sticky="nsew")
        #line 14
        label14 = tk.Label(self, text='', width=10)
        label14.grid(row=14, column=0, sticky='w')
        buttonhlp = tk.Button(self, text="Help", width=20, height = 3,
                              command=lambda: controller.show_frame("help"))
        buttonhlp.grid(row=14, column=1, columnspan=4)
        label14 = tk.Label(self, text='')
        label14.grid(row=14, column=5, columnspan=2)
        buttonquit = tk.Button(self, text="Quit", width=20, height = 3, command=close_window)
        buttonquit.grid(row=14, column=7, columnspan=4)
        label14 = tk.Label(self, text='', width=10)
        label14.grid(row=14, column=11, sticky='e')
        #line 15
        label15 = tk.Label(self, text='', height=5)
        label15.grid(row=15, column=0, columnspan=12, sticky="nsew")


class page1(tk.Frame):

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

        #line 0
        label00 = tk.Label(self, text='PAGE1', height=2)
        label00.configure(relief='raised')
        label00.grid(row=13, column=0, columnspan=12, sticky="nsew")
        #line 1
        label10 = tk.Label(self, text='', width=10)
        label10.grid(row=14, column=0, sticky='w')
        buttonback = tk.Button(self, text="Back", width=20, height = 3,
                              command=lambda: controller.show_frame("MainPage"))
        buttonback.grid(row=14, column=1, columnspan=4)
        label10= tk.Label(self, text='')
        label10.grid(row=14, column=5, columnspan=2)
        buttonquit = tk.Button(self, text="Quit", width=20, height = 3, command=close_window)
        buttonquit.grid(row=14, column=7, columnspan=4)
        label10 = tk.Label(self, text='', width=10)
        label10.grid(row=14, column=11, sticky='e')
        #line 2
        label20 = tk.Label(self, text='', height=5)
        label20.grid(row=15, column=0, columnspan=12, sticky="nsew")

class help(tk.Frame):

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

        #line 0
        label00 = tk.Label(self, text='HELP', height=2)
        label00.configure(relief='raised')
        label00.grid(row=13, column=0, columnspan=12, sticky="nsew")
        #line 1
        label10 = tk.Label(self, text='', width=10)
        label10.grid(row=14, column=0, sticky='w')
        buttonback = tk.Button(self, text="Back", width=20, height = 3,
                              command=lambda: controller.show_frame("MainPage"))
        buttonback.grid(row=14, column=1, columnspan=4)
        label10= tk.Label(self, text='')
        label10.grid(row=14, column=5, columnspan=2)
        buttonquit = tk.Button(self, text="Quit", width=20, height = 3, command=close_window)
        buttonquit.grid(row=14, column=7, columnspan=4)
        label10 = tk.Label(self, text='', width=10)
        label10.grid(row=14, column=11, sticky='e')
        #line 2
        label20 = tk.Label(self, text='', height=5)
        label20.grid(row=15, column=0, columnspan=12, sticky="nsew")


def close_window ():
    app.destroy()


if __name__ == "__main__":
    app = MainApp()

    app.overrideredirect(True)
    app.geometry("{0}x{1}+0+0".format(app.winfo_screenwidth(), app.winfo_screenheight()))
    app.focus_set()  # <-- move focus to this widget


    app.mainloop()

So actually I want that when open page1 frame, in label00 I want to see time that I print in the beginning of the code.

lucian_v
  • 111
  • 3
  • 12

2 Answers2

8

You should use the after method, so as to periodically update the label displaying the time. The following post provides in-depth explanations on how to do so: How to use the after method to make a callback run periodically?

Let's build a minimal example. First off, I need a root, and a label:

import tkinter as tk
root = tk.Tk()
label = tk.Label(root, text="placeholder")
label.pack()

Now, I need a function that will set the current time in the label. As explained in the Q/A I linked to, I need this function to call itself. Since I want the label to be refreshed as fast as possible, I will ask the function to call itself after one millisecond. The time module could be used, but the datetime module wraps the latter so as to provide human-readable time.

import datetime
def set_label():
    currentTime = datetime.datetime.now()
    label['text'] = currentTime
    root.after(1, set_label)

Now I will call the set_label function, in order to start the loop, and then call root.mainloop so as to enter the application's loop:

set_label()
root.mainloop()

All together:

import tkinter as tk
import time

def set_label():
    currentTime = datetime.datetime.now()
    label['text'] = currentTime
    root.after(1, set_label)

root = tk.Tk()
label = tk.Label(root, text="placeholder")
label.pack()

set_label()
root.mainloop()
Right leg
  • 16,080
  • 7
  • 48
  • 81
  • Why are you calling your function 1000 times per second, when you know that the displayed value will change only once per second? – Bryan Oakley Sep 18 '17 at 12:31
  • @BryanOakley That's not entirely true, since the value provided by `datetime.now()` goes down to microseconds. However, I have to admit that this raises the valid question whether or not it is appropriate to update the label more frequently than once per second. I guess it all depends on the user's needs. – Right leg Sep 18 '17 at 12:35
0

One way to do it would be to periodically call a function and update the GUI. In Tkinter this is usually done by using the universal widget method after.

I've modified your code to create a StringVar attribute to hold the time value and use after() to call a new clock() method which has also been added to your MainApp class. All this method does is update the StringVar attribute of the class instance.

The other thing I did was modify the __init__() method of the your Page1 class to use the textvariable option instead of the text option when creating the label00 widget, and to specify the StringVar attribute that was added to the MainApp class as its value.

The nice thing about doing this is the label will be updated automatically whenever the value of the variable changes. In addition, you can reference this same attribute from different parts of the GUI as needed.

Note I only modified the label00 attribute of your Page1 class...you'll need to do something similar to the other places you want the current time displayed. (They can all use the same StringVar attribute.)

import time
import datetime
import Tkinter as tk
from Tkinter import *

class MainApp(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.timevar = tk.StringVar()  # Added.

        self.frames = {}
        for F in (MainPage, Page1, Help):
            page_name = F.__name__
            frame = F(parent=container, controller=self)
            self.frames[page_name] = frame
            frame.grid(row=0, column=0, columnspan=12,sticky="nsew")
            frame.grid_columnconfigure(0, weight=1)
            frame.grid_columnconfigure(1, weight=1)
            frame.grid_columnconfigure(2, weight=1)
            frame.grid_columnconfigure(3, weight=1)
            frame.grid_columnconfigure(4, weight=1)
            frame.grid_columnconfigure(5, weight=1)
            frame.grid_columnconfigure(6, weight=1)
            frame.grid_columnconfigure(7, weight=1)
            frame.grid_columnconfigure(8, weight=1)
            frame.grid_columnconfigure(9, weight=1)
            frame.grid_columnconfigure(10, weight=1)
            frame.grid_columnconfigure(11, weight=1)

        # Synchronize with the computer's clock.
        snooze = (1000000 - datetime.datetime.now().microsecond) / 1000000.
        if snooze > 0:
            time.sleep(snooze)  # Sleep until next whole second.
        self.clock()  # Starts string variable update process.

        self.show_frame("MainPage")

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

    # Additional method added.
    def clock(self):
        self.timevar.set(datetime.datetime.now().strftime("Time: %H:%M:%S"))
        self.after(1000, self.clock)  # Update every second (1000 millsecs)


class MainPage(tk.Frame):

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

        # line 0
        label00 = tk.Label(self, text='00', height=2)
        label00.configure(relief='raised')
        label00.grid(row=0, column=0, sticky='nsew', columnspan=12)
        # line 1
        label10 = tk.Label(self, text='10')
        label10.configure(relief='raised')
        label10.grid(row=1, column=0, sticky='nsew')
        label11 = tk.Label(self, text='LOGO')
        label11.configure(relief='raised')
        label11.grid(row=1, column=1, sticky='nsew', columnspan=4, rowspan=2)
        label12 = tk.Label(self, text='12')
        label12.configure(relief='raised')
        label12.grid(row=1, column=5, sticky='nsew')
        label13 = tk.Label(self, text='TITLE')
        label13.configure(relief='raised')
        label13.grid(row=1, column=6, sticky='nsew', columnspan=5)
        label14 = tk.Label(self, text='14')
        label14.configure(relief='raised')
        label14.grid(row=1, column=11, sticky='nsew')
        # line 2
        label20 = tk.Label(self, text='20')
        label20.configure(relief='raised')
        label20.grid(row=2, column=0, sticky='nsew')
        label21 = tk.Label(self, text='21')
        label21.configure(relief='raised')
        label21.grid(row=2, column=5, sticky='nsew')
        label22 = tk.Label(self, text='Desc')
        label22.configure(relief='raised')
        label22.grid(row=2, column=6, sticky='nsew', columnspan=5)
        label23 = tk.Label(self, text='23')
        label23.configure(relief='raised')
        label23.grid(row=2, column=11, sticky='nsew')
        # line 3
        label30 = tk.Label(self, text='30', height=2)
        label30.configure(relief='raised')
        label30.grid(row=3, column=0, sticky='nsew', columnspan=12)
        #line 4
        label40 = tk.Label(self, text='40', width=10)
        label40.configure(relief='raised')
        label40.grid(row=4, column=0, sticky='nsew')
        label41 = tk.Label(self, text='STATUS', font=("Helvetica", 16), justify='center', fg="blue")
        label41.configure(relief='raised')
        label41.grid(row=4, column=1, columnspan=10)
        label42 = tk.Label(self, text='42', width=10)
        label42.configure(relief='raised')
        label42.grid(row=4, column=11, sticky='nsew')
        #line 5
        label50 = tk.Label(self, text='50', height=2)
        label50.configure(relief='raised')
        label50.grid(row=5, column=0, columnspan=12, sticky="nsew")
        #line 6
        label60 = tk.Label(self, text='60', height=2)
        label60.configure(relief='raised')
        label60.grid(row=6, column=0, sticky='nsew')
        buttonauto = tk.Button(self, text="PAGE1", font=("Helvetica", 16), justify='center', width=40, height=5,
                              command=lambda: controller.show_frame("Page1"))
        buttonauto.grid(row=6, column=1, columnspan=4)
        label61 = tk.Label(self, text='61', height=2)
        label61.configure(relief='raised')
        label61.grid(row=6, column=5, sticky='nsew')
        label62 = tk.Label(self, text='62', height=2)
        label62.configure(relief='raised')
        label62.grid(row=6, column=6, sticky='nsew')
        buttoncam = tk.Button(self, text="HELP",font=("Helvetica", 16), justify='center', width=40, height=5,
                              command=lambda: controller.show_frame("Help"))
        buttoncam.grid(row=6 , column=7, columnspan=4)
        label63 = tk.Label(self, text='63', height=2)
        label63.configure(relief='raised')
        label63.grid(row=6, column=11, sticky='nsew')
        # line 7
        label70 = tk.Label(self, text='70', height=2)
        label70.configure(relief='raised')
        label70.grid(row=7, column=0, sticky='nsew', columnspan=12)

        #line 13
        label13 = tk.Label(self, text='', height=2)
        label13.configure(relief='raised')
        label13.grid(row=13, column=0, columnspan=12, sticky="nsew")
        #line 14
        label14 = tk.Label(self, text='', width=10)
        label14.grid(row=14, column=0, sticky='w')
        buttonhlp = tk.Button(self, text="Help", width=20, height = 3,
                              command=lambda: controller.show_frame("Help"))
        buttonhlp.grid(row=14, column=1, columnspan=4)
        label14 = tk.Label(self, text='')
        label14.grid(row=14, column=5, columnspan=2)
        buttonquit = tk.Button(self, text="Quit", width=20, height = 3, command=close_window)
        buttonquit.grid(row=14, column=7, columnspan=4)
        label14 = tk.Label(self, text='', width=10)
        label14.grid(row=14, column=11, sticky='e')
        #line 15
        label15 = tk.Label(self, text='', height=5)
        label15.grid(row=15, column=0, columnspan=12, sticky="nsew")


class Page1(tk.Frame):

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

        #line 0
#        label00 = tk.Label(self, text='PAGE1', height=2)
        label00 = tk.Label(self, textvariable=controller.timevar, height=2)
        label00.configure(relief='raised')
        label00.grid(row=13, column=0, columnspan=12, sticky="nsew")
        #line 1
        label10 = tk.Label(self, text='', width=10)
        label10.grid(row=14, column=0, sticky='w')
        buttonback = tk.Button(self, text="Back", width=20, height = 3,
                              command=lambda: controller.show_frame("MainPage"))
        buttonback.grid(row=14, column=1, columnspan=4)
        label10= tk.Label(self, text='')
        label10.grid(row=14, column=5, columnspan=2)
        buttonquit = tk.Button(self, text="Quit", width=20, height = 3, command=close_window)
        buttonquit.grid(row=14, column=7, columnspan=4)
        label10 = tk.Label(self, text='', width=10)
        label10.grid(row=14, column=11, sticky='e')
        #line 2
        label20 = tk.Label(self, text='', height=5)
        label20.grid(row=15, column=0, columnspan=12, sticky="nsew")

class Help(tk.Frame):

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

        #line 0
        label00 = tk.Label(self, text='HELP', height=2)
        label00.configure(relief='raised')
        label00.grid(row=13, column=0, columnspan=12, sticky="nsew")
        #line 1
        label10 = tk.Label(self, text='', width=10)
        label10.grid(row=14, column=0, sticky='w')
        buttonback = tk.Button(self, text="Back", width=20, height = 3,
                              command=lambda: controller.show_frame("MainPage"))
        buttonback.grid(row=14, column=1, columnspan=4)
        label10= tk.Label(self, text='')
        label10.grid(row=14, column=5, columnspan=2)
        buttonquit = tk.Button(self, text="Quit", width=20, height = 3, command=close_window)
        buttonquit.grid(row=14, column=7, columnspan=4)
        label10 = tk.Label(self, text='', width=10)
        label10.grid(row=14, column=11, sticky='e')
        #line 2
        label20 = tk.Label(self, text='', height=5)
        label20.grid(row=15, column=0, columnspan=12, sticky="nsew")


def close_window ():
    app.destroy()


if __name__ == "__main__":
    app = MainApp()

    app.overrideredirect(True)
    app.geometry("{0}x{1}+0+0".format(app.winfo_screenwidth(), app.winfo_screenheight()))
    app.focus_set()  # <-- move focus to this widget


    app.mainloop()
martineau
  • 119,623
  • 25
  • 170
  • 301
  • why are you calling the function four times a second if the value only changes once a second? – Bryan Oakley Sep 18 '17 at 14:43
  • @Bryan: Because the rate of update should be greater than once a second since it's not synchronized to occur at the top of a minute. Suppose it could be, though. Probably could get by with every ½ second...but a little more than necessary probably isn't going to hurt much. IMO you should stick to more egregious issues that folks have in their tkinter code (just my opinion). – martineau Sep 18 '17 at 17:48
  • If this click were being used to time an olympic race, sub-second accuracy could be important. For anything else, it's just wasting CPU cycles. – Bryan Oakley Sep 18 '17 at 17:50
  • @Bryan: OK, point taken...although to get close to one second accuracy I still believe updating more frequently than that would be required (not knowing the exact application). – martineau Sep 18 '17 at 18:01
  • @Bryan: I modified the code in my answer to only update once a second, but sync with the computer's clock first. Hope you find it suitable now. – martineau Sep 18 '17 at 18:45
  • 1
    It's not a matter of me finding it suitable. It's a matter of not teaching bad habits to beginners. – Bryan Oakley Sep 18 '17 at 18:49