tkinter locking in function

0

To do a mini-programinha to be used in the work / study hours style the pomodoro method. I made it very simple, quick, but when I press to start, the program locks exactly the time that was put and only comes back when everything is finished, to try to find the error I left with 3 seconds each interval and time of service, then it is stopped until finished all. In this there are some visual changes that should take place on the TV, such as showing the cycles and what stage it is, but nothing moves, and only comes back when everything goes. Here is the code:

from tkinter import *
from time import sleep

# Action
def pomodoro():
    lb_acao['text'] = 'Pomodori'
    lb_acao['bg'] = 'red'
    qt_ciclos = int(ed_ciclos.get())

    while qt_ciclos >= 0:
        lb_ciclos_restantes['text'] = qt_ciclos
        sleep(3)

        lb_acao['text'] = 'Intervalo'
        lb_acao['bg'] = 'green'
        sleep(3)

        lb_acao['text'] = 'Pomodori'
        lb_acao['bg'] = 'red'

        qt_ciclos -= 1

win = Tk()

# Components
lb1 = Label(win, text='Tempo útil: ')
ed_tempo = Entry(win)

lb2 = Label(win, text='Tempo de intervalo: ')
ed_intervalo = Entry(win)

lb3 = Label(win, text='Quantidade de ciclos: ')
ed_ciclos = Entry(win)

btn = Button(win, text='Começar', command=pomodoro)

lb4 = Label(win, text='Ciclos restantes:')
lb_ciclos_restantes = Label(win, text='0')

lb5 = Label(win, text='Modo:')
lb_acao = Label(win, text='Preparado')

lb6 = Label(win, text='Tempo:')
lb_time = Label(win)

# GUI
lb1.grid(row=0, column=0)
ed_tempo.grid(row=0, column=1)

lb2.grid(row=1, column=0)
ed_intervalo.grid(row=1, column=1)

lb3.grid(row=2, column=0)
ed_ciclos.grid(row=2, column=1)

btn.grid(row=3, column=0, columnspan=2, sticky=W+E)


lb4.grid(row=4, column=0)
lb_ciclos_restantes.grid(row=4, column=1)
lb5.grid(row=5, column=0)
lb_acao.grid(row=5, column=1)
lb6.grid(row=6, column=0)
lb_time.grid(row=6, column=1)

# Program
win.mainloop()

So this is characteristic of tkinter, which does not allow you to constantly tinker with your look. Or is there something wrong that I'm not fixing?

Thanks ....

    
asked by anonymous 25.04.2018 / 06:51

1 answer

0

This happens because your program is synchronous. That means he only does one thing at a time. When you call sleep , the program stops executing that particular time, and while it is sleeping it neither updates the screen nor even hears the interface to know if the user gave some command; in this, it is locked, although it returns when the time of "asleep" ends.

The solution is to use the after function of Tk. You give it the number of milliseconds you want to wait and a function; Tkinter then performs that function after the given number of milliseconds.

That means you have to split your pomodoro function into some parts, so you can wait between them. As we also have to remember in which cycle we are in different functions, we add a global variable. Here, I called it from ciclo_atual , and I kept the waiting 3s from the original code:

from tkinter import *

# Quando o botão é clicado, resetamos o contador de ciclo atual
# e iniciamos o primeiro ciclo.
def pomodoro():
    global ciclo_atual
    ciclo_atual = 0
    iniciar_ciclo()

# Quando iniciamos um ciclo, verificamos se o contador extrapolou
# a quantidade de ciclos desejada. Se não, chamamos a função
# iniciar_intervalo depois de 3000 milisegundos.
def iniciar_ciclo():
    global ciclo_atual
    lb_acao['text'] = 'Pomodori'
    lb_acao['bg'] = 'red'
    qt_ciclos = int(ed_ciclos.get())
    lb_ciclos_restantes['text'] = qt_ciclos - ciclo_atual

    if ciclo_atual < qt_ciclos:
        ciclo_atual += 1
        win.after(3000, iniciar_intervalo)

# Ao iniciar o intervalo, atualizamos a interface e chamamos
# novamente a função iniciar_ciclo depois de 3000 ms.
def iniciar_intervalo():
    lb_acao['text'] = 'Intervalo'
    lb_acao['bg'] = 'green'
    win.after(3000, iniciar_ciclo)


win = Tk()

# Components
lb1 = Label(win, text='Tempo útil: ')
ed_tempo = Entry(win)

lb2 = Label(win, text='Tempo de intervalo: ')
ed_intervalo = Entry(win)

lb3 = Label(win, text='Quantidade de ciclos: ')
ed_ciclos = Entry(win)

btn = Button(win, text='Começar', command=pomodoro)

lb4 = Label(win, text='Ciclos restantes:')
lb_ciclos_restantes = Label(win, text='0')

lb5 = Label(win, text='Modo:')
lb_acao = Label(win, text='Preparado')

lb6 = Label(win, text='Tempo:')
lb_time = Label(win)

# GUI
lb1.grid(row=0, column=0)
ed_tempo.grid(row=0, column=1)

lb2.grid(row=1, column=0)
ed_intervalo.grid(row=1, column=1)

lb3.grid(row=2, column=0)
ed_ciclos.grid(row=2, column=1)

btn.grid(row=3, column=0, columnspan=2, sticky=W+E)


lb4.grid(row=4, column=0)
lb_ciclos_restantes.grid(row=4, column=1)
lb5.grid(row=5, column=0)
lb_acao.grid(row=5, column=1)
lb6.grid(row=6, column=0)
lb_time.grid(row=6, column=1)

# Program
win.mainloop()
    
25.04.2018 / 17:04