[EKB] This is a simple task timer I built using [clock.tcl] (last updated 15 Dec. 2005). Here's what it looks like: [http://www.kb-creative.net/screenshots/Timer.gif] It's set to be [always on top], at least on Windows. It combines a clock with a timer. The "copy to clipboard" feature pastes the date, start time, and time elapsed (in hours) to the clipboard, separated by tabs, then resets the timer: Tue, 13 Sep 2005 17:30 0.25 The reason for this is that it can then be pasted into a table (e.g., [TkTable], Excel, OpenOffice.org Calc) for easy manipulation. It can also be pasted straight into a text file. I then type in the project & task information, and keep going. I use this to keep track of my billed time. Here's a typical workflow: 1. Click the "start/pause/stop" button when starting a task. 1. Click the "start/pause/stop" to pause & restart when taking a break. 1. When done with the task, click "paste to clipboard" and paste into log. If there's an error, then click "reset" to reset the timer. Here's the code: ###################################################### ## ## Always on top, no resize ## ###################################################### wm attributes . -topmost 1 wm resizable . 0 0 ###################################################### ## ## Buttons ## ###################################################### image create photo appclock16 -data { R0lGODlhEAAPAIQAAPwCBARCZKze7Kza5IzK3ITC1KTS5Hy2zGyuxGSmvFyW tFyavEyStEyOrESGrDx+pDRynCRqlBxejAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQAA8AAAVOICCKQTCe KBAIgpmiwUAM7ksORUHbpHH8LV6AgCgidq/AIcFkImEJhWIxXdROAQWD0eA2 rqNAw0Emg8OPdPochrgh7HBkHg9LJHVs3R4CACH+aENyZWF0ZWQgYnkgQk1Q VG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4g QWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29t ADs= } image create photo apppause16 -data { R0lGODlhDwAPAIMAAPwCBARCZKze7JTO3Hy2zITC1GyqxGSmvFyavGSixEyO tESGrDx+pDRynAAAAAAAACH5BAEAAAAALAAAAAAPAA8AAARFEMhJq7016KlD FqAXgILHDQQhoioVFIYhwrJLGId4566BICIf0JVQKETFowuxWIiYTpeCwRBN qy5GoyHScjMbSQdDLl8iACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZl cnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyBy ZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs= } image create photo record16 -data { R0lGODlhEAAQAIUAAIx+bIx6bIR6bIRyZHxyZHxuXHRqXPwCBOTe3Nze3HRm XIR2ZPz+/GxiVPz29GRaTGReVFxWTHxuZPzy5Ly2rFxSRPTq3OzexLyulFRK RKyqrPTizLyihExKRMTCxGxeVOzWvERCPFxSTOzSrLyabLSytGRaVOTKpEQ+ NLy+vMS+tMS2nLymhDw2NExGPMSulMSqjDw6NDQ2LAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAcALAAAAAAQABAAAAal QEBAMCAUDIekUhlAJBJOhWK5XCQYWEbD8aAmB9csBBKJeCVhhmOSoFQeR6Uh vLZcMBlNQppUINQTFhsXHB0eDB9cBw0JdYMgHCGHHw8PIh8JgRcXICMkkmsJ JRUmCYKcIyckKCmBG3gRKhQrGBy2qyWnLB0iFRkdHSEhKC0tJYMjkV4uGikl JajKVBGmj6mrXrErKy8wLCQkMV4VFcDCKCEtMn5BACH+aENyZWF0ZWQgYnkg Qk1QVG9HSUYgUHJvIHZlcnNpb24gMi41DQqpIERldmVsQ29yIDE5OTcsMTk5 OC4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3Iu Y29tADs= } ###################################################### ## ## "Minimalist" balloon help from Tcler's Wiki ## ## With modest change so that there isn't much delay ## while browsing over buttons. ## ###################################################### namespace eval balloon { variable long_delay 750 variable short_delay 50 variable delay $long_delay variable family {} } bind . { if {$balloon::family != ""} { if {[lsearch -exact $balloon::family %W] == -1} { set balloon::family {} set balloon::delay $balloon::long_delay } } } proc set_balloon {w help} { bind $w "+after \$balloon::delay [list balloon::show %W [list $help]]; set balloon::delay $balloon::short_delay; set balloon::family \[balloon::getwfamily %W\]" bind $w "+destroy %W.balloon" } # Add these to the namespace proc balloon::getwfamily {w} { return [winfo children [winfo parent $w]] } proc balloon::show {w arg} { if {[eval winfo containing [winfo pointerxy .]]!=$w} {return} set top $w.balloon catch {destroy $top} toplevel $top -bd 1 -bg black wm attributes $top -topmost 1 wm overrideredirect $top 1 if {$::tcl_platform(platform) == "macintosh"} { unsupported1 style $top floating sideTitlebar } pack [message $top.txt -aspect 10000 -bg lightyellow -padx 1 -pady 0 \ -text $arg] set wmx [expr [winfo rootx $w]+5] set wmy [expr [winfo rooty $w]+[winfo height $w]+7] wm geometry $top \ [winfo reqwidth $top.txt]x[winfo reqheight $top.txt]+$wmx+$wmy raise $top } ###################################################### ## ## Timer procs ## ###################################################### proc every {ms body} { eval $body after $ms [list every $ms $body] } proc timeElapsed {sec} { set hours [expr {$sec / 3600}] set mins [expr {($sec / 60) % 60}] return [format "%02d:%02d" $hours $mins] } # Are we timing, or not? set timer(state) 0 # Has the timer been reset? set timer(reset) 1 # Store previous time elapsed set timer(prev) 0 proc toggleTimer {b} { if {$::timer(state)} { $b config -relief flat $b config -image appclock16 set ::timer(state) 0 set ::timer(prev) [expr {$::timer(prev) + [clock sec] - $::timer(init)}] } else { $b config -relief sunken $b config -image apppause16 if {$::timer(reset)} { set ::timer(reset) 0 } set ::timer(init) [clock sec] set ::timer(state) 1 } } proc resetTimer {b} { set ::timer(reset) 1 set ::timer(elapsed) "00:00" set ::timer(init) [clock sec] set ::timer(prev) 0 } proc recordTime {b} { # Stop timing if {$::timer(state)} { toggleTimer $b } # Save info set date [clock format [clock sec] -format "%a, %d %b %Y"] set start "--:--" if [info exists ::timer(init)] { set start [fmtTime $::timer(init)] } set elapsed [unfmtTime $::timer(elapsed)] # Reset the timer resetTimer $b clipboard clear clipboard append -type STRING "$date\t$start\t$elapsed" } proc fmtTime {sec} { return [clock format $sec -format %H:%M] } # unfmtTime: Take H:M and return decimal hours proc unfmtTime {s} { set t [split $s ":"] set hr [string trimleft [lindex $t 0] "0"] if {$hr == ""} {set hr 0} set min [string trimleft [lindex $t 1] "0"] if {$min == ""} {set min 0} set hr [expr {0.01 * round(100 * ($hr + (1.0 * $min)/60))}] return [format "%.2f" $hr] } proc updateTimer {} { set ::timer(now) [fmtTime [clock sec]] if {$::timer(state)} { set elapsed_sec [expr {$::timer(prev) + [clock sec] - $::timer(init)}] set ::timer(elapsed) [timeElapsed $elapsed_sec] } } ## -- Top frame pack [frame .top] -side top pack [label .top.l -textvar timer(now) -font {Tahoma 18}] -side left -padx 6 # Buttons pack [frame .top.buttons] -side right -padx 6 set clockbutton [button .top.buttons.t -image appclock16 -relief flat \ -width 16] pack $clockbutton -side left set recordbutton [button .top.buttons.rec -image record16 -relief flat] pack $recordbutton -side left ## -- Bottom frame pack [frame .bottom] -side bottom pack [label .bottom.l -textvar timer(elapsed) -font {Tahoma 10}] $clockbutton config -command "toggleTimer $clockbutton" set_balloon $clockbutton "Start/stop timer" $recordbutton config -command "recordTime $clockbutton" set_balloon $recordbutton "Clear and save to clipboard" ###################################################### ## ## Start program! ## ###################################################### set timer(elapsed) "00:00" every 1000 updateTimer ---- [EKB] With the magic of [Freewrap], this is now available to the world as a Windows executable: [http://tasktimer.kb-creative.net/] ---- Thanks for writing this app. I've found it really useful. It's just so cool how contributions feed on each other: some simple test code, someone expands it for usefulness, and then releases it to the world. [EKB] That's great! Thanks for posting this. ---- see also [multiple timers] ---- [Category Date and Time] | [Category Application] ---- '''[bigote] - 2009-07-07 20:05:33''' Hello, I'm quite a beginner in Tcl and it's the first time I write here so please forgive me if I do something wrong :) With your permission I would like to share my small modification made to the Task Timer. It's a cosmetic change but now it looks like a WindowMaker applet. Well, I suppose if there's something wrong with the font size on your system, it wouldn't, but it could be corrected easily changing font face and/or size in the lines ====== set cur_timer [label .top.l -textvar timer(now) -font {Arial 8 bold}] and pack [label .top.timer.l -textvar timer(elapsed) -font {Tahoma 8}] ====== I even use this newly baked applet instead of wmcalclock. I just added another tooltip that shows the current date when pointing the mouse at the current time. I also had to adapt the code to Linux environment (added command ''package require Tk'' and commented out two identic lines ''wm attributes . -topmost 1''). So here goes the diff. You can copy and paste it into a file (for instance, patch.diff) and then apply the patch to the source file (let it be tasktimer.tcl) using Unix ''patch'' command after placing patch.diff next to it: ====== patch -p0 < patch.diff ====== Here you have a http://gnuwin32.sourceforge.net/packages/patch.htm%|%Windows version of patch%|%. ====== --- tasktimer.tcl 2009-07-08 01:43:56.000000000 +0200 +++ ttmr.tcl 2009-07-08 01:47:37.000000000 +0200 @@ -1,9 +1,25 @@ +#!/bin/sh +# the next line restarts using wish \ +exec wish "$0" "$@" $argv;# -geometry +800+0 + +#This program is written by EKB http://wiki.tcl.tk/13772 +#Its code can be found at http://wiki.tcl.tk/14707 + +#This modification is made by Serge Yudin (xmpp:bigote@jabber.ru) +#and consists of geometry changes (now it looks like a wm-applet). +#Also a tooltip added that shows the current date when pointing +#the cursor at the current time. The window size could vary depending +#on font size. Please hack it yourself if it's too big or too small. + +package require Tk ###################################################### ## ## Always on top, no resize ## ###################################################### - wm attributes . -topmost 1 +#This line is commented out because it gave me an error +#when running in Linux. (SY) +# wm attributes . -topmost 1 wm resizable . 0 0 ###################################################### @@ -87,7 +103,7 @@ set top $w.balloon catch {destroy $top} toplevel $top -bd 1 -bg black - wm attributes $top -topmost 1 +# wm attributes $top -topmost 1 wm overrideredirect $top 1 if {$::tcl_platform(platform) == "macintosh"} { unsupported1 style $top floating sideTitlebar @@ -164,7 +180,7 @@ clipboard append -type STRING "$date\t$start\t$elapsed" } proc fmtTime {sec} { - return [clock format $sec -format %H:%M] + return [clock format $sec -format %H:%M:%S] } # unfmtTime: Take H:M and return decimal hours @@ -188,10 +204,10 @@ ## -- Top frame pack [frame .top] -side top - pack [label .top.l -textvar timer(now) -font {Tahoma 18}] -side left -padx 6 - + set cur_timer [label .top.l -textvar timer(now) -font {Arial 8 bold}] + pack $cur_timer -side top -padx 2 # Buttons - pack [frame .top.buttons] -side right -padx 6 + pack [frame .top.buttons] -side bottom -padx 6 set clockbutton [button .top.buttons.t -image appclock16 -relief flat \ -width 16] pack $clockbutton -side left @@ -199,13 +215,14 @@ pack $recordbutton -side left ## -- Bottom frame - pack [frame .bottom] -side bottom - pack [label .bottom.l -textvar timer(elapsed) -font {Tahoma 10}] + pack [frame .top.timer] -side top + pack [label .top.timer.l -textvar timer(elapsed) -font {Tahoma 8}] $clockbutton config -command "toggleTimer $clockbutton" set_balloon $clockbutton "Start/stop timer" $recordbutton config -command "recordTime $clockbutton" set_balloon $recordbutton "Clear and save to clipboard" + set_balloon $cur_timer "[clock format [clock seconds] -format {%A, %d of %B %Y}]" ###################################################### ## ====== ---- '''[bigote] - 2009-07-07 20:11:44''' Oh-oh, I knew I would do something wrong. Now my comment is placed below category name. If someone knows how to correct this and, even better, how to avoid this, please let me know :)