A Second Counter using Tkinter GUI

vegaseat 1 Tallied Votes 3K Views Share

Using count() from Python's itertools module and the Tkinter GUI toolkit's after() function, you can create a simple counter that counts up the seconds until the Stop button is pressed.

# a second counter using Tkinter
# tested with Python25  by  vegaseat  17aug2007

import Tkinter as tk
from itertools import count

def start_counter(label):
    counter = count(0)
    def update_func():
        label.config(text=str(counter.next()))
        label.after(1000, update_func)  # 1000ms
    update_func()


root = tk.Tk()
root.title("Counting Seconds")
label = tk.Label(root, fg="red")
label.pack()
start_counter(label)
button = tk.Button(root, text='Stop', width=30, command=root.destroy)
button.pack()
root.mainloop()

Dani AI

Generated

Nice tip from . One gotcha with second counters is drift: if you increment an integer every callback, small scheduling delays accumulate. A robust pattern is to compute the display from a monotonic clock and let Tk’s event loop simply schedule UI updates. time.monotonic() is immune to system clock changes, so pauses, DST shifts, or NTP adjustments do not skew your elapsed time. Also store the after() id and cancel it with after_cancel() to stop cleanly without leaving pending callbacks. (docs.python.org, tcl.tk)

If you are running this on Python 3, remember the module name is lowercase tkinter (it was Tkinter in Python 2). (docs.python.org)

# Python 3
import tkinter as tk
import time

class SecondCounter:
    def __init__(self, root):
        self.root = root
        self.t0 = None           # running start time
        self.elapsed = 0.0       # accumulated seconds while paused
        self.after_id = None

        self.label = tk.Label(root, font=("Segoe UI", 24), text="0")
        self.label.pack(padx=10, pady=10)

        tk.Button(root, text="Start", command=self.start).pack(side="left")
        tk.Button(root, text="Stop",  command=self.stop).pack(side="left")
        tk.Button(root, text="Reset", command=self.reset).pack(side="left")

    def start(self):
        if self.after_id is not None:
            return  # already running
        if self.t0 is None:
            self.t0 = time.monotonic()
        self.tick()

    def stop(self):
        if self.after_id:
            self.root.after_cancel(self.after_id)
            self.after_id = None
        if self.t0 is not None:
            self.elapsed += time.monotonic() - self.t0
            self.t0 = None

    def reset(self):
        self.stop()
        self.elapsed = 0.0
        self.label.config(text="0")

    def tick(self):
        running = (time.monotonic() - self.t0) if self.t0 else 0.0
        self.label.config(text=str(int(self.elapsed + running)))
        self.after_id = self.root.after(200, self.tick)  # UI stays responsive

root = tk.Tk()
SecondCounter(root)
root.mainloop()

Notes:

  • Pass a callable to after (no parentheses); cancel with the returned id to avoid multiple timers. The Tk after command schedules callbacks in the event loop and does not guarantee exact wall-clock delays on a busy UI thread. (tcl.tk)
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.