Search code examples
pythonuser-interfacetkintertimercountdown

python GUI countdown timer (don't use classes)


i have just one problem in my source code, lbl_time will not change, all thing running well except this. I could only use function in my program, if someone can help me in this functional program, please do it.

import tkinter as tk
from datetime import timedelta
import winsound

set time is a function that for counting down time, i use timedelta for building a time object to simple operation

def main():
    def set_time(hours:int=0, minutes:int=0, seconds:int=0):
        end = timedelta(hours=hours, minutes=minutes, seconds=seconds)
        one_second = timedelta(seconds=1)
        result = end - one_second
        new_time = seconds_to_hms(result.seconds)
        if result.seconds is 0:
            while True:
                try:
                    winsound.PlaySound("Ringtones\\1.cookie clock.wav", winsound.SND_FILENAME)
                except KeyboardInterrupt:
                    break
        else:
            hours, minutes, seconds = new_time.get('hours'), new_time.get('minutes'), new_time.get('seconds')
            time.set(str(hours)+':'+str(minutes)+':'+str(seconds))
            root.update()
            root.after(1000, lambda : set_time(hours, minutes, seconds))

    def seconds_to_hms(seconds:int) -> dict:
        hours, minutes, seconds = 0, 0, seconds
        if seconds >= 3600:
            hours = seconds//3600
            seconds = seconds - hours*3600
        if seconds >= 60:
            minutes = seconds//60
            seconds = seconds - minutes*60
        result = {'hours': hours, 'minutes': minutes, 'seconds': seconds}
        return result

    def quit(*args):
        root.destroy()

    root = tk.Tk()
    root.title(string='Timer')
    time = tk.StringVar()
    root.configure(background='black')
    logo = tk.PhotoImage(file='Logo.png')
    lbl_logo = tk.Label(root, image=logo, bg='black').pack(side='right')
    lbl_timer = tk.Label(root, padx=10, text="Timer", fg='white', bg='black', font='Times 24', anchor='center').pack()
    lbl_time = tk.Label(root, text=time, font="Times 38", fg='white', bg='black').pack()
    btn_start = tk.Button(root, text='start', bg='gray', fg='black', command=lambda : set_time()).pack()
    root.bind('x', quit)
    root.after(1000, lambda : set_time(0,0, 3))
    root.mainloop()




if __name__ == '__main__':
    main()

enter image description here


Solution

  • Took some time to understand your question, but I might have solved your problem.

    1. Fundamentally you ought to have used textvariable rather than text as an argument in your lbl_time declaration.

    2. If your while loop is executed, it might result in an infinite loop, you might want to have an increment if the code branches there.

    Do check out the following, you might want to uncomment some of the lines, hopefully it does solve your problem:

    import tkinter as tk
    from datetime import timedelta
    import winsound
    def main():
        def set_time(hours:int=0, minutes:int=0, seconds:int=0):
            end = timedelta(hours=hours, minutes=minutes, seconds=seconds)
            one_second = timedelta(seconds=1)
            result = end - one_second
            new_time = seconds_to_hms(result.seconds)
            if result.seconds is 0:
                while True:
                    try:
                        winsound.PlaySound("Ringtones\\1.cookie clock.wav", winsound.SND_FILENAME)
                    except KeyboardInterrupt:
                        break
            else:
                hours, minutes, seconds = new_time.get('hours'), new_time.get('minutes'), new_time.get('seconds')
                time.set(str(hours)+':'+str(minutes)+':'+str(seconds))
                root.update()
                root.after(1000, lambda : set_time(hours, minutes, seconds))
    
        def seconds_to_hms(seconds:int) -> dict:
            hours, minutes, seconds = 0, 0, seconds
            if seconds >= 3600:
                hours = seconds//3600
                seconds = seconds - hours*3600
            if seconds >= 60:
                minutes = seconds//60
                seconds = seconds - minutes*60
            result = {'hours': hours, 'minutes': minutes, 'seconds': seconds}
            return result
    
        def quit(*args):
            root.destroy()
    
        root = tk.Tk()
        root.title(string='Timer')
        time = tk.StringVar()
        root.configure(background='black')
      #  logo = tk.PhotoImage(file='Logo.png')
      #  lbl_logo = tk.Label(root, image=logo, bg='black').pack(side='right')
        lbl_timer = tk.Label(root, padx=10, text="Timer", fg='white', bg='black', font='Times 24', anchor='center').pack()
        lbl_time = tk.Label(root, textvariable=time, font="Times 38", fg='white', bg='black').pack() #changed text to textvariable
        btn_start = tk.Button(root, text='start', bg='gray', fg='black', command=lambda :set_time(0,0,3700)).pack()
        root.bind('x', quit)
        #root.after(1000, lambda : set_time(0,0, 3))
        root.mainloop()
    
    
    if __name__ == '__main__':
        main()