Home > Net >  Python Tkinter: Countdown Timer is very laggy and not accurate
Python Tkinter: Countdown Timer is very laggy and not accurate

Time:05-26

I made a countdown timer using Tkinter in python, but it's very and the seconds aren't real seconds (the timer is faster than it should be).

The after() function of tkinter doesn't wait exactly the specified amount of time, so I can't just substract 1 millisecond every time it waits 1 millisecond using after(1), it wouldn't be accurate. So now the program finds the exact amount of time that has passed while waiting 1ms with after(1) and then substract this amount from the timer.

Could anyone suggest an edit or just edit my program to solve these problems?

Here's the program:


from tkinter import *
import time
import datetime

class root(Tk):
    def __init__(self):
        super(root, self).__init__()

        self.title("Timer")
        
        self.buttonplay = Button(self, text = "Play", fg= 'green', command = self.play)
        self.buttonplay.pack()

        self.buttonpause = Button(self, text = "Pause", fg = "red", command=self.pause)
        self.buttonpause.pack()
        
        self.buttonreset = Button(self, text = "Reset", fg = "red", command=self.reset)
        self.buttonreset.pack()

        self.createTimers()

    def play(self):
        self.timeit=True
        self.timer1.configure(bg='#1C953D')
        self.doTimer()

    def pause(self):
        self.timeit=False
        self.timer1.configure(bg='#454545')
        
    def reset(self):
        self.timer1.destroy()
        self.createTimers()

    def createTimers(self):
        self.total_minute = 1
        self.total_second = 5
        self.total_micros = 0
        self.total = self.total_second   self.total_minute *60   self.total_micros*0.000001

        self.originalTime = datetime.datetime.now()
        self.micros = self.originalTime.microsecond
        self.seconds = self.originalTime.second
        self.minutes = self.originalTime.minute

        self.time1 = StringVar()
        self.time1.set(str(self.total_minute).rjust(2, '0')   ':'   str(self.total_second).rjust(2, '0')  '.'  str(self.total_micros)[0:3].rjust(3, '0'))
        self.timer1 = Label(self, textvariable=self.time1, bg='#454545', fg='white', font ="Gadugi 40 bold")
        self.timer1.pack()
        self.timer1.configure(bg='#454545')

    def doTimer(self):
        if (self.total_second   self.total_minute *60   self.total_micros*0.000001) >0: #Checks if the timer ended
            if self.timeit:
                self.nowTime = datetime.datetime.now()
                self.toDim = self.nowTime.microsecond
                while self.toDim > 0:
                    if self.micros > 0:
                        self.micros = self.micros -1
                        self.toDim = self.toDim -1
                    else:
                        if self.seconds > 0:
                            self.seconds = self.seconds -1
                            self.micros = 999999
                        else:
                            self.minutes = self.minutes -1
                            self.seconds = 59
                self.DimTime = datetime.datetime(self.originalTime.year, self.originalTime.month, self.originalTime.day, self.originalTime.hour, self.minutes, self.seconds, self.micros)
                self.waitMicros = self.originalTime - self.DimTime

                self.total_micros = self.total_micros - self.waitMicros.microseconds
                if self.total_micros <0:
                    self.total_second = self.total_second -1
                    self.total_micros = 999999
                if self.total_second <0:
                    self.total_minute = self.total_minute -1
                    self.total_second = 59


                self.time1.set(str(self.total_minute).rjust(2, '0')   ':'   str(self.total_second).rjust(2, '0')  '.'  str(self.total_micros)[0:3].rjust(3, '0'))

                self.after(1, self.doTimer)
        else:
            self.time1.set('00:00.000')
            self.timer1.configure(bg='#FF0000')
            self.after(3000, self.reset)


root = root()
root.mainloop()

Here's a video showing the problem.

CodePudding user response:

def play(self):
    self.timeit = True
    self.timer1.configure(bg='#1C953D')

    self.start_time = time.time()
    self.total_start = self.seconds   self.minutes * 60   self.micros * 0.000001
    self.doTimer()

def pause(self):
    self.timeit = False
    self.timer1.configure(bg='#454545')

def reset(self):
    self.timer1.destroy()
    self.createTimers()

def createTimers(self):
    self.start_time = time.time()
    self.minutes = 1
    self.seconds = 5
    self.micros = 0
    self.total_start = self.seconds   self.minutes * 60   self.micros * 0.000001

    self.time1 = StringVar()
    self.time1.set(str(self.minutes).rjust(2, '0')   ':'   str(self.seconds).rjust(2, '0')   '.'   str(
        self.micros)[0:3].rjust(3, '0'))
    self.timer1 = Label(self, textvariable=self.time1, bg='#454545', fg='white', font="Gadugi 40 bold")
    self.timer1.pack()
    self.timer1.configure(bg='#454545')

def doTimer(self):
    if (self.seconds   self.minutes * 60   self.micros * 0.000001) > 0:  # Checks if the timer ended
        if self.timeit:
            self.time_left = self.start_time - time.time()   self.total_start
            self.minutes = int(self.time_left) // 60
            self.seconds = int(self.time_left) % 60
            self.micros = int((self.time_left - int(self.time_left)) * 1000000)
            self.time1.set(
                str(self.minutes).rjust(2, '0')   ':'   str(self.seconds).rjust(2, '0')   '.'   str(
                    self.micros)[0:3].rjust(3, '0'))

        self.after(1, self.doTimer)
    else:
        self.time1.set('00:00.000')
        self.timer1.configure(bg='#FF0000')
        self.after(3000, self.reset)
  • Related