0

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.

The_Fishy
  • 143
  • 10

1 Answers1

0
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)
Ze'ev Ben-Tsvi
  • 1,174
  • 1
  • 3
  • 7
  • 1
    This answer isn't very useful without a description of what you changed. We have to compare your code to the original line-by-line and character-by-character to see what has changed. – Bryan Oakley May 25 '22 at 14:32