Date updated on Tkinter

1

I want to do an accountant in Tkinter little by little. At the moment I want you to show me the date in seconds (yes, I know it's a bit weird ...) through this function:

def Date_secondsnow():
    now = datetime.now()
    Datesecondsnow = now.second + now.minute*60 + now.hour*60*60 + now.day*24*60*60 + now.month*30*24*60*60 + now.year*365*24*60*60
    return Datesecondsnow

The previous function shows the present date approximately in seconds. The question is to try to appear in a label, that date updated second by second.

Conditions:

  • Do it without defining any class (if possible)

I tried to do it by putting this snippet of code at the end of my program:

while True:
    Display()

but it does not work for me, the second to second date is not updated (Display () is described below). The "start" and "stop" buttons do the same thing but I do not care at the moment.

The code is as follows:

import tkinter as tk
from tkinter import *
from random import randint
from datetime import datetime, date, time, timedelta

#DECLARACIÓN DE FUNCIONES

def Date_secondsnow():
    now = datetime.now()
    Datesecondsnow = now.second + now.minute*60 + now.hour*60*60 + now.day*24*60*60 + now.month*30*24*60*60 + now.year*365*24*60*60
    return Datesecondsnow


def starcounter():
    labelQuestion = tk.Label(frame, text=str(Date_secondsnow()), padx=10 )
    labelQuestion.grid(row=0, column=0, sticky=tk.W)

def Display():
    labelQuestion = tk.Label(frame, text=str(Date_secondsnow()), padx=10 )
    labelQuestion.grid(row=0, column=0, sticky=tk.W)





#Creando una ventanta principal
window=tk.Tk()
window.geometry("500x300+100+100")
window.title("Cronómetro")

#Creamos un frame como contenedor
frame = tk.Frame(window)





#Creando un label para mostrar la cuenta
#labelQuestion = tk.Label(frame, text="Cuenta", padx=10 )
#labelQuestion.grid(row=0, column=0, sticky=tk.W)
labelQuestion = tk.Label(frame, text=str(Date_secondsnow()), padx=10 )
labelQuestion.grid(row=0, column=0, sticky=tk.W)


#Definimos un tamaño mínimo de la fila central delgrid para que quede un espacio entre cada entry y posicionamos el frame
frame.grid_rowconfigure(1, minsize=10)
frame.place(x=0,y=140)

#Creando un botón para Iniciar
btnSave=tk.Button(window,text="Iniciar",command=starcounter,font=("Agency FB",14))
btnSave.place(x=130,y=210)

#Creando un botón para Parar
btnStop=tk.Button(window,text="Parar",command=starcounter,font=("Agency FB",14))
btnStop.place(x=190,y=210)

#Iniciamos el mailoop
window.mainloop()
#App = Display(master=root)

Thank you very much in advance.

    
asked by Mr. Baldan 26.08.2017 в 09:52
source

1 answer

1

The first premise in any GUI is never to use blocking methods in the mainloop . This ends up causing the mainloop to crash so the GUI stops responding when it can not respond to new events and redraw properly. If you use a while cycle within your main thread, your GUI will simply be blocked.

You must execute the code in charge of updating label implementing some asynchronous method. There are several ways, the simplest way is to use callbacks next to the after method:

import tkinter as tk
from datetime import datetime


def Date_secondsnow():
    now = datetime.now()
    date_seconds_now = now.second + now.minute*60 + now.hour*60*60 + now.day*24*60*60 + now.month*30*24*60*60 + now.year*365*24*60*60
    return date_seconds_now

def set_date():
    if state.get():
        date_seconds.set(Date_secondsnow())
        labelQuestion.after(250, set_date)

def start_counter():
    state.set(True)
    set_date()

def stop_counter():
    state.set(False)

window=tk.Tk()
window.geometry("500x300+100+100")
window.title("Cronómetro")

frame = tk.Frame(window)

date_seconds = tk.IntVar(value = 0)
state = tk.BooleanVar(value = False)

labelQuestion = tk.Label(frame, textvariable=date_seconds, padx=10 )
labelQuestion.grid(row=0, column=0, sticky=tk.W)

frame.grid_rowconfigure(1, minsize=10)
frame.place(x=0,y=140)

btnSave=tk.Button(window, text="Iniciar", command=start_counter, font=("Agency FB", 14))
btnSave.place(x=130,y=210)

btnStop=tk.Button(window, text="Parar", command=stop_counter, font=("Agency FB", 14))
btnStop.place(x=190,y=210)

window.mainloop()

Basically the idea is:

  • We use a Tk-Variable ( IntVar ) to show the date in the Label. The fun of this is that you can share between methods, functions and threads safely and without using global . On the other hand, the content of the Label is updated when its associated variable is modified automatically.

  • We use another Tk-Variable ( BooleanVar ) to specify the state and be able to stop the "clock" whenever you want.

  • after is used to update Label without blocking the GUI. Basically it allows to call a function / method with a certain delay without blocking the mainloop during the wait. It must be clear that the function does not run asynchronously , only the wait is (and it is during this period when the mainloop can update the interface). If the function takes a long time to return the interface will be blocked, in these cases you have to resort to other methods, such as using threads.

In this case, the date is checked every quarter of a second (250 milliseconds). Depending on the accuracy and the load to the system that we want, this can be modified.

  

Note: Using the form from módulo import * to import is a bad   practice to be avoided ( PEP 8 - Imports ). It hinders the readability of the code and   can cause errors when overwriting some method   unconsciously. "Explicit better than implied" .

Exit:

    
answered by 26.08.2017 / 13:18
source