Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Tkinter window in python not responding

I have a countdown program (code below) that should start counting down from whatever length of time you have put in (you all know how a timer works, right?). But the tkinter window simply freezes when you press start but does not return any error until a windows error message saying that the window is not responding pops up. I have included some print statements as I was trying to debug it and it shows in shell that the program is working as it repeatedly prints c .Does anyone know how to sort out this problem?

import tkinter as tk
import time

def change(direction, stringvar, up_button, down_button):
    if direction == 'up':
        stringvar.set(stringvar.get()+1)
        down_button.config(state = 'normal')
        if int(stringvar.get())== 59:
            up_button.config(state = 'disabled')
    if direction == 'down':
        stringvar.set(stringvar.get()-1)
        up_button.config(state = 'normal')
        if stringvar.get()== 0:
            down_button.config(state = 'disabled') 

def startTimer():
    hourEntry.destroy()
    minuteEntry.destroy()
    secondEntry.destroy()
    print('a')
    hourLab = tk.Label(root, textvariable = hourText)
    minuteLab = tk.Label(root, textvariable = minuteText)
    secondLab = tk.Label(root, textvariable = secondText)
    print('b')
    hourLab.grid(row = 1, column = 0)
    minuteLab.grid(row = 1, column = 1)
    secondLab.grid(row = 1, column = 2)
    while hourText.get() != 0 or minuteText != 0 or secondText !=0:
        print('c')
        time.sleep(1)
        secondText.set(secondText.get()-1)
        if int(secondText.get()) == 0:
            secondText.set(59)
            if int(minuteText.get()) == 0:
                if int(hourText.get()) == 0:
                    continue
                else:
                    hourText.set(str(int(hourText.get())-1))
            else:
                minuteText.set(str(int(minuteText.get())-1))
root = tk.Tk()
root.title('Timer')
hourText = tk.IntVar()
minuteText = tk.IntVar()
secondText = tk.IntVar()
hourText.set(1)
minuteText.set(1)
secondText.set(1)
## create buttons and entry boxes using loop
up1 = tk.Button(root, text = '^^^', command = lambda: change('up', hourText, up1, down1))
up2 = tk.Button(root, text = '^^^', command = lambda: change('up', minuteText, up2, down2))
up3 = tk.Button(root, text = '^^^', command = lambda: change('up', secondText, up3, down3))
hourEntry = tk.Entry(root, textvariable = hourText, width = 5)
minuteEntry = tk.Entry(root, textvariable = minuteText, width = 5)
secondEntry = tk.Entry(root, textvariable = secondText, width = 5)
down1 = tk.Button(root, text = '...', command = lambda: change('down', hourText, up1, down1))
down2 = tk.Button(root, text = '...', command = lambda: change('down', minuteText, up2, down2))
down3 = tk.Button(root, text = '...', command = lambda: change('down', secondText, up3, down3))
start = tk.Button(root, text = 'Start', command = startTimer)
up1.grid(row = 0, column = 0, pady = 5, padx = 5)
up2.grid(row = 0, column = 1)
up3.grid(row = 0, column = 2, padx = 5)
hourEntry.grid(row = 1, column = 0, padx = 2, pady = 5)
minuteEntry.grid(row = 1, column = 1, padx = 2, pady = 5)
secondEntry.grid(row = 1, column = 2, padx = 2, pady = 5)
down1.grid(row = 2, column = 0)
down2.grid(row = 2, column = 1)
down3.grid(row = 2, column = 2)
start.grid(row = 3, columnspan = 3, pady = 5)
root.mainloop()
like image 922
Morosophist Avatar asked Sep 22 '26 21:09

Morosophist


1 Answers

To implement your program :

import tkinter as tk
import time

def change(direction, stringvar, up_button, down_button):
    if direction == 'up':
        stringvar.set(stringvar.get()+1)
        down_button.config(state = 'normal')
        if int(stringvar.get())== 59:
            up_button.config(state = 'disabled')
    if direction == 'down':
        stringvar.set(stringvar.get()-1)
        up_button.config(state = 'normal')
        if stringvar.get()== 0:
            down_button.config(state = 'disabled') 

def timer():
    if hourText.get() != 0 or minuteText != 0 or secondText !=0:
        print('c')
        time.sleep(1)
        secondText.set(secondText.get()-1)
        if int(secondText.get()) == 0:
            secondText.set(59)
            if int(minuteText.get()) == 0:
                if int(hourText.get()) == 0:
                    pass
                else:
                    hourText.set(str(int(hourText.get())-1))
            else:
                minuteText.set(str(int(minuteText.get())-1))
        root.after(1, timer)

def startTimer():
    hourEntry.destroy()
    minuteEntry.destroy()
    secondEntry.destroy()
    print('a')
    hourLab = tk.Label(root, textvariable = hourText)
    minuteLab = tk.Label(root, textvariable = minuteText)
    secondLab = tk.Label(root, textvariable = secondText)
    print('b')
    hourLab.grid(row = 1, column = 0)
    minuteLab.grid(row = 1, column = 1)
    secondLab.grid(row = 1, column = 2)
    root.after(1, timer)
        
root = tk.Tk()
root.title('Timer')
hourText = tk.IntVar()
minuteText = tk.IntVar()
secondText = tk.IntVar()
hourText.set(1)
minuteText.set(1)
secondText.set(1)
## create buttons and entry boxes using loop
up1 = tk.Button(root, text = '^^^', command = lambda: change('up', hourText, up1, down1))
up2 = tk.Button(root, text = '^^^', command = lambda: change('up', minuteText, up2, down2))
up3 = tk.Button(root, text = '^^^', command = lambda: change('up', secondText, up3, down3))
hourEntry = tk.Entry(root, textvariable = hourText, width = 5)
minuteEntry = tk.Entry(root, textvariable = minuteText, width = 5)
secondEntry = tk.Entry(root, textvariable = secondText, width = 5)
down1 = tk.Button(root, text = '...', command = lambda: change('down', hourText, up1, down1))
down2 = tk.Button(root, text = '...', command = lambda: change('down', minuteText, up2, down2))
down3 = tk.Button(root, text = '...', command = lambda: change('down', secondText, up3, down3))
start = tk.Button(root, text = 'Start', command = startTimer)
up1.grid(row = 0, column = 0, pady = 5, padx = 5)
up2.grid(row = 0, column = 1)
up3.grid(row = 0, column = 2, padx = 5)
hourEntry.grid(row = 1, column = 0, padx = 2, pady = 5)
minuteEntry.grid(row = 1, column = 1, padx = 2, pady = 5)
secondEntry.grid(row = 1, column = 2, padx = 2, pady = 5)
down1.grid(row = 2, column = 0)
down2.grid(row = 2, column = 1)
down3.grid(row = 2, column = 2)
start.grid(row = 3, columnspan = 3, pady = 5)
root.mainloop()

Tkinter uses a method (Tk.after) that allow the user to overcome the tk mainloop. (The window does not wait for the function to finish).

It allows us to update manually all the widgets (canvas, button, label [ect...])

This is a method I always use in my tkinter applications, because I don't trust tk.mainloop () to do what I want.

like image 192
wartonbega Avatar answered Sep 26 '26 03:09

wartonbega



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!