Hello everyone!
I've started developing a little application for one of my friends,
which he will use at work to measure his hours working + the time he
has breaks. I wanna do this in python cause, I just started with this
language and wanna get more fimiliar with it. Sometimes though, it's a
bit of a struggle.

I found a nice stopwatch using tkinter, and I've modified it a bit to
my needs. The only thing I'm missing now is he wan't a pause counter,
for how long the pause button has been pushed.
An example:
I've worked for 2 hours, and wanna go for a break, I push the pause button.
The pause counter then starts ticking, until the start button is
pressed again. So I have both a counter for working hours and pause
hours. If the pause button is pressed again, the current time he has
kept his break can't be reset, so it has to add the new time it to the
current.
I hope that made sense.

My code is below or on http://pastebin.com/T8FkMusS

#! /usr/bin/python
# Author : Morten Klim Sørensen - mail@kl1m.dk
# Created: 2011 Jul 17
# Filename: stopwatch2.py
# Description:

from tkinter import *
import time
import pickle
from datetime import datetime

DataFile = 'Tider.txt'
class StopWatch(Frame):  
    """ Implements a stop watch frame widget. """                                                                
    def __init__(self, parent=None, **kw):        
        Frame.__init__(self, parent, kw)
        self._start = 0.0        
        self._elapsedtime = 0.0
        self._pausestart = 0.0
        self._elapsedpause = 0.0
        self._running = 0
        self.timestr = StringVar()               
        self.makeWidgets()      

    def makeWidgets(self):                         
        """ Make the time label. """
        l = Label(self, textvariable=self.timestr)
        self._setTime(self._elapsedtime)
        l.grid(row=0)
    
    def _update(self): 
        """ Update the label with elapsed time. """
        self._elapsedtime = time.time() - self._start
        self._setTime(self._elapsedtime)
        self._timer = self.after(50, self._update)
    
    def _updatepause(self):
        self._elapsedpause = time.time() - self._pausestart
        self._setTime(self._elapsedpause)
        self._timer = self.after(50, self._updatepause)
    
    def _setTime(self, elap):
        """ Set the time string to Hours:Minutes:Seconds """
        hours = int(elap/60/60)
        if hours >= 1:
            minutes = int(elap/60 - hours*60.0)
            seconds = int(elap - 3600*hours - (minutes * 60))
        else:
            minutes = int(elap/60)
            seconds = int(elap - minutes*60.0)
        #mseconds = int((elap - minutes*60.0 - seconds)*100)                
        self.timestr.set('%02d:%02d:%02d' % (hours, minutes, seconds))
        
    def Start(self):                                                     
        """ Start the stopwatch, ignore if running. """
        if not self._running:            
            self._start = time.time() - self._elapsedtime
            self._update()
            self._running = 1        
    
    def Stop(self):                                    
        """ Stop the stopwatch, ignore if stopped. """
        if self._running:
            self.after_cancel(self._timer)            
            self._elapsedtime = time.time() - self._start
            self._setTime(self._elapsedtime)
            self._running = 0

            self._pausestart = time.time() - self._elapsedpause
            self._updatepause()
    
    def Reset(self):                                  
        """ Reset the stopwatch. """
        self._start = time.time()         
        self._elapsedtime = 0.0    
        self._setTime(self._elapsedtime)

    def Export(self):
        """ Export date and time elapsed to file """
        current_file = ""
        try:
            current_file = pickle.load( open(DataFile, 'rb') )
        except:
            print("File Not Found")

        print(self._pausestart)
        print(self._elapsedpause)
        hours = int(self._elapsedtime/60/60)
        minutes = int(self._elapsedtime/60 - hours*60.0)
        f = open(DataFile, 'wb')
        pickle.dump(current_file + "\n" + time.strftime("%d-%m-%Y") + " - Arbejdstimer: {0}t:{1}m  |  Pause: {2}\n".format(str(hours), str(minutes), str("42")), f)
        f.close()
        
        
def main():
    root = Tk()
    root.title("Det gode stopur")
    sw = StopWatch(root)
    sw.grid(row=0, columnspan=4)

    Button(root, text='Start', command=sw.Start).grid(row=1, column=0)
    Button(root, text='Pause', command=sw.Stop).grid(row=1, column=1)
    Button(root, text='Reset', command=sw.Reset).grid(row=1, column=2)
    Button(root, text='Quit', command=root.quit).grid(row=1, column=3)
    Button(root, text='Export', command=sw.Export).grid(row=2, column=1)

    Label(root, text="Morten Klim Sørensen - www.kl1m.dk").grid(row=3, columnspan=4)
    
    root.mainloop()

if __name__ == '__main__':
    main()

# End of stopwatch2.py

The variables at __init__

self._pausestart = 0.0 
self._elapsedpause = 0.0

and the method _updatepause are a attempt to make this work. They make the GUI timer go crazy, if for that to work proper remove them.


I've tried a little for my self and tried another bit more easy method.
This I runned, when you push the "Pause" button.

def _updatepause(self):
       global pseconds, pminutes, phours
       while self._IsPause:
            time.sleep(1.0) #sleep 1sec
            pseconds += 1
            if pseconds == 60:
                pseconds = 0; pminutes += 1
                if pminutes == 60:
                    pminutes = 0; phours += 1

Though this make the whole GUI freeze (not responding), which is pretty obvious. I just don't know how to solve that. It's counting fine though, when I kill the app I see the variables have some data.

Regards,
Morten

timer_update -> if Paused do nothing else put to label current_time - paused_time - start_time
Pause pushed ->
if in Paused state add current_time - pause_start_time to paused_time
else save current_time to pause_start_time.

Why you are used capitalized object names (like Reset) for methods? If you have not any super good reason hold to PEP8 standard.

Edited 5 Years Ago by pyTony: n/a

timer_update -> if Paused do nothing else put to label current_time - paused_time - start_time
Pause pushed ->
if in Paused state add current_time - pause_start_time to paused_time
else save current_time to pause_start_time.

Why you are used capitalized object names (like Reset) for methods? If you have not any super good reason hold to PEP8 standard.

Thanks for your reply.
I've tried your idea, and it seems to work. The only thing is, that it only updates paused_time once and that's when I click the Stop button. I need it to loop through this, but how do I do this?

Here is the new code:

#! /usr/bin/python
# Author : Morten Klim Sørensen - mail@kl1m.dk
# Created: 2011 Jul 17
# Filename: stopwatch2.py
# Description:

from tkinter import *
import time
import pickle
from datetime import datetime

DataFile = 'Tider.txt'

class StopWatch(Frame):  
    """ Implements a stop watch frame widget. """                                                                
    def __init__(self, parent=None, **kw):        
        Frame.__init__(self, parent, kw)
        self._start = 0.0        
        self._elapsedtime = 0.0
        self._running = 0
        self._isPause = False
        self._pausedTime = 0.0
        self._pauseStartTime = 0.0
        self.timestr = StringVar()               
        self.makeWidgets()      

    def makeWidgets(self):                         
        """ Make the time label. """
        l = Label(self, textvariable=self.timestr)
        self._setTime(self._elapsedtime)
        l.grid(row=0)
    
    def _update(self):
        """ Update the label with elapsed time. """
        if not self._isPause:
            self._elapsedtime = time.time() - self._pausedTime - self._start
            self._setTime(self._elapsedtime)
            self._timer = self.after(50, self._update)
            self._pauseStartTime = time.time()
        else:
            self._pausedTime = time.time() - self._pauseStartTime
    
     
    def _setTime(self, elap):
        """ Set the time string to Hours:Minutes:Seconds """
        hours = int(elap/60/60)
        if hours >= 1:
            minutes = int(elap/60 - hours*60.0)
            seconds = int(elap - 3600*hours - (minutes * 60))
        else:
            minutes = int(elap/60)
            seconds = int(elap - minutes*60.0)
        #mseconds = int((elap - minutes*60.0 - seconds)*100)                
        self.timestr.set('%02d:%02d:%02d' % (hours, minutes, seconds))
        
    def Start(self):                                                     
        """ Start the stopwatch, ignore if running. """
        if not self._running:
            self._isPause = False
            self._start = time.time() - self._elapsedtime
            self._update()
            self._running = 1        
    
    def Stop(self):                                    
        """ Stop the stopwatch, ignore if stopped. """
        if self._running:
            self._isPause = True
            self.after_cancel(self._timer)            
            self._elapsedtime = time.time() - self._start
            self._setTime(self._elapsedtime)
            self._running = 0
            self._update()
                
    def Reset(self):                                  
        """ Reset the stopwatch. """
        self._start = time.time()         
        self._elapsedtime = 0.0    
        self._setTime(self._elapsedtime)

    def Export(self):
        """ Export date and time elapsed to file """
        current_file = ""
        try:
            current_file = pickle.load( open(DataFile, 'rb') )
        except:
            print("File Not Found")

        print("Pause Hours: {0} Min: {1} Sec: {2}".format(phours, pminutes, pseconds))
        print("_pausedTime: " + str(self._pausedTime))
        print("_pauseStartTime: " + str(self._pauseStartTime))
        hours = int(self._elapsedtime/60/60)
        minutes = int(self._elapsedtime/60 - hours*60.0)
        f = open(DataFile, 'wb')
        pickle.dump(current_file + "\n" + time.strftime("%d-%m-%Y") + " - Arbejdstimer: {0}t:{1}m  |  Pause: {2}\n".format(str(hours), str(minutes), str("42")), f)
        f.close()
        
        
def main():
    root = Tk()
    root.title("Det gode stopur")
    sw = StopWatch(root)
    sw.grid(row=0, columnspan=4)

    Button(root, text='Start', command=sw.Start).grid(row=1, column=0)
    Button(root, text='Pause', command=sw.Stop).grid(row=1, column=1)
    Button(root, text='Reset', command=sw.Reset).grid(row=1, column=2)
    Button(root, text='Quit', command=root.quit).grid(row=1, column=3)
    Button(root, text='Export', command=sw.Export).grid(row=2, column=1)

    Label(root, text="Morten Klim Sørensen - www.kl1m.dk").grid(row=3, columnspan=4)
    
    root.mainloop()

if __name__ == '__main__':
    main()

# End of stopwatch2.py

I haven't been naming all the methods my self, actually I only made _updatepause and Export. The others are just modified from an stopwatch I found, which used these names.

Edited 5 Years Ago by KLIM8D: n/a

okay, got my last problem solved. Just needed to add this, in the _update else:

self._timer = self.after(50, self._update)

The pause counts now correctly, and starts and stops when either Start or Pause is pushed, but it reset though. When I push start, the values keeps being the same until the Pause is pushed again for the second time. The value is now reset to 0 and counting up once again.
I've tried to add it's own value to itself

self._pausedTime = self._pausedTime - time.time() - self._pauseStartTime

but didn't work out as expected, I only got a long minus number. How can I be sure it stores the last paused time and just add more time to the current paused time?

Did you check my code snippet for my simple version for comparison?

I don't see any code snippet in you last post.

Work and pause timer

Thanks for the help. Your code was a bit too advanced for my skills of python yet, but some of your code helped a lot.
I ended up adding the pause times to a list, and taking the sum of that in the end.

You can then mark the thread solved and possibly upvote and give reputation to helpfull posts. My code was quite basic except using the attribute of function for static values of function instead of globals.

Glad to listen you found a way suitable for your current understanding. My experience is, that after one month you would like to recode it, so use good variable names and meaningfull comments/docstrings to make the maintanance easy according to Python spirit.

P.S. Did you anytime try this:

import this

It is good thing to look sometimes to remind what Python is all about.

Lycka till!

Edited 5 Years Ago by pyTony: n/a

This question has already been answered. Start a new discussion instead.