Home > Software design >  Timer that prints elapsed time and resets with a button click
Timer that prints elapsed time and resets with a button click

Time:11-01

I have a GUI where the user can click a button named "next set" that allows them to move onto the next task. I wanted to add a timer that starts as soon as they start the application and run the timer until they press the button "next set". When clicked, I want the time elapsed to print and the timer to restart until they press "next set" button again. I would like the timer to start automatically when the code runs. Currently, the "next set" button has two actions, one is to retrieve the next set of images and the other action I am trying to include is to reset the timer and print time elapsed. I also only included part of the code that felt relevant because it is long.

import time
import tkinter as tk
import csv
from pathlib import Path
import PIL.Image
import PIL.ImageDraw
import PIL.ImageTk
MAX_HEIGHT = 500

IMAGES_PATH = Path("Images")

CSV_LABELS_KEY = "New Labels"
CSV_FILE_NAME_KEY = "FolderNum_SeriesNum"
CSV_BOUNDING_BOX_KEY = "correct_flip_bbox"
counter = 0
timer_id = None
class App(tk.Frame):
    def __init__(self, master=None):
        super().__init__(master)  # python3 style
        self.config_paths = ["config 1.yaml", "config 2.yaml", "config 3.yaml"]
        self.config_index = 0
        self.clickStatus = tk.StringVar()
        self.loadedImages = dict()
        self.loadedBoxes = dict()  # this dictionary will keep track of all the boxes drawn on the images
        self.master.title('Slideshow')
        frame = tk.Frame(self)
        tk.Button(frame, text="  Next set ", command=lambda:[self.get_next_image_set(), self.reset()]).pack(side=tk.RIGHT)
        tk.Button(frame, text="  Exit  ", command=self.destroy).pack(side=tk.RIGHT)
        frame.pack(side=tk.TOP, fill=tk.BOTH)
        self.canvas = tk.Canvas(self)
        self.canvas.pack()
        self._load_dataset()

        self.reset()
        self.start_timer = None
        t = time()
        t.start()

    def start_timer(self, evt=None):
        if self._start_timer is not None:
        self._start_timer = time.perf_counter()

    # global counter
    # counter  = 1
    # label.config(text=str(counter))
    # label.after(1000, count)

    def reset(self):
        if self._start_timer is None:

        elapsed_time = time.perf_counter() - self._start_timer
        self._start_timer = None
        print('Time elapsed (hh:mm:ss.ms) {}'.format(elapsed_time))


    def _load_dataset(self):
        try:
            config_path = self.config_paths[self.config_index]
            self.config_index  = 1
        except IndexError:
            return
        image_data = loadData(config_path)
        # drawing the image on the label
        self.image_data = image_data
        self.currentIndex = 0
        # start from 0th image
        self._load_image()

    def _load_image(self):
        imgName = self.image_data[self.currentIndex]['image_file']
        if imgName not in self.loadedImages:

            self.im = PIL.Image.open(self.image_data[self.currentIndex]['image_file'])
            ratio = MAX_HEIGHT / self.im.height
            # ratio divided by existing height -> to get constant amount
            height, width = int(self.im.height * ratio), int(self.im.width * ratio)
            # calculate the new h and w and then resize next
            self.canvas.config(width=width, height=height)
            self.im = self.im.resize((width, height))
            if self.im.mode == "1":
                self.img = PIL.ImageTk.BitmapImage(self.im, foreground="white")
            else:
                self.img = PIL.ImageTk.PhotoImage(self.im)
            imgData = self.loadedImages.setdefault(self.image_data[self.currentIndex]['image_file'], dict())
            imgData['image'] = self.img
            imgData['shapes'] = self.image_data[self.currentIndex]['shapes']
        # for next and previous so it loads the same image adn don't do calculations again
        self.img = self.loadedImages[self.image_data[self.currentIndex]['image_file']]['image']
        self.canvas.create_image(0, 0, anchor=tk.NW, image=self.img)
        self.show_drag_box()

def loadData(fname):
    with open(fname, mode='r') as f:
        return yaml.load(f.read(), Loader=yaml.SafeLoader)


if __name__ == "__main__":
    data = loadData('config 1.yaml')
    app = App(data)
    app.pack()  # goes here
    app.mainloop()

CodePudding user response:

I have used datetime instead of time, as subtracting two datetime objects will give an output with hours and minutes included, whereas subtracting two time objects only gives seconds. However, both will work, you may just need to do more reformatting using time.

Read the current time when the application starts and store it. Each time you press the button, subtract your stored time from the current time which gives you your time elapsed. Then simply store your new current time until the next button press. The code below demonstrates this.

import tkinter as tk
import datetime as dt

class TimeButton(tk.Frame):
  def __init__(self, parent):
    super().__init__(parent)

    # Start timer
    self.current_time = dt.datetime.today()

    # Button
    self.next_set = tk.Button(self, text='Next Set', command = self.clicked)
    self.next_set.pack()

  def clicked(self):
    now = dt.datetime.today()
    time_elapsed = now - self.current_time
    
    print(time_elapsed)
    self.current_time = now


if __name__ == "__main__":
  window = tk.Tk()
  button = TimeButton(window)
  button.pack()
  window.mainloop()
  • Related