FF - 2008-07-01 - Since people asked what TrackerWidget is for, here's is an example (still incomplete) of some of its features.
N.B.: requires TrackerWidget saved in a tracker.tcl file in current directory.

#!/usr/bin/env wish
source tracker.tcl
trace add variable ::wm_title write set_wm_title
proc set_wm_title {name _ op} {
if {$::wm_title != {}} {
wm title . "HexEdit - $::wm_title"
} else {
wm title . "HexEdit"
}
}
proc menu_open {} {
global filename
set f [tk_getOpenFile]
if {$f != {}} {set filename $f; jump_to_offset 0 0; set ::wm_title $filename}
}
proc menu_save {} {
global filename
tk_messageBox -icon warning -type ok -message "Not implemented yet!" -detail "Time for looking at the code? ;-P"
}
proc menu_save_as {} {
global filename
tk_messageBox -icon warning -type ok -message "Not implemented yet!" -detail "Time for looking at the code? ;-P"
#set f [tk_getSaveFile -initialfile $filename]
}
proc help_about {} {
set e [string map {R ri O co Q de Z fe I it W ma L il} [email protected]]
tk_messageBox -icon info -type ok -message "hexedit (a demo of tracker widget)\nby Federico Ferri <$e> - 2008\n\nhttps://wiki.tcl-lang.org/FF\n" -title "About"
}
proc help_dwim {} {
tk_messageBox -icon question -type ok -message "Wouldn't that be nice?" -detail "I almost finished the algorithm and I'll release it soon! :)"
}
proc jump_to_offset {kb b} {
global filename
if ![file exists $filename] {return}
set fh [open $filename r]
seek $fh [expr {1024*$kb+$b}]
for {set row 0} {$row < 64} {incr row} {
.ta setdata $row 0 [expr {16*$row+1024*$kb+$b}]
for {set col 0} {$col < 16} {incr col} {
set ch [read $fh 1]
if {$ch != {} && [scan $ch %c ascii]} {
.t setdata $row $col $ascii
} else {
.t setdata $row $col {}
}
}
}
close $fh
}
proc yset {n args} {
uplevel 1 [linsert $args 0 .vs set]
if {$n != 1} {uplevel 1 [list .ta yview moveto [lindex [.vs get] 0]]}
if {$n != 2} {uplevel 1 [list .t yview moveto [lindex [.vs get] 0]]}
if {$n != 3} {uplevel 1 [list .tb yview moveto [lindex [.vs get] 0]]}
}
proc yview {args} {
uplevel 1 [linsert $args 0 .ta yview]
uplevel 1 [linsert $args 0 .t yview]
uplevel 1 [linsert $args 0 .tb yview]
}
proc update_cursor {r c} {
.ta moveabs $r 0
.tb moveabs $r $c
}
proc update_sel {sr sc er ec} {
.ta setsel $sr 0 $er 0
.tb setsel $sr $sc $er $ec
}
proc update_data {r c d} {
.tb setdata $r $c $d
}
set ::wm_title {}
menu .mb
. configure -menu .mb
menu .mb.f -tearoff 0
.mb.f add command -label {Open...} -command menu_open
.mb.f add command -label {Save} -command menu_save
.mb.f add command -label {Save as...} -command menu_save_as
.mb.f add separator
.mb.f add command -label {Exit} -command {exit}
.mb add cascade -label {File} -menu .mb.f
menu .mb.e -tearoff 0
.mb.e add command -label {Cut} -command {.t cut}
.mb.e add command -label {Copy} -command {.t copy}
.mb.e add command -label {Paste} -command {.t paste}
.mb.e add command -label {Delete} -command {.t delete}
.mb.e add separator
.mb.e add command -label {Select all} -command {.t select_all}
.mb.e add command -label {Select none} -command {.t select_none}
.mb.e add command -label {Select row} -command {.t select_row}
.mb.e add command -label {Select column} -command {.t select_column}
.mb add cascade -label {Edit} -menu .mb.e
menu .mb.h -tearoff 0
.mb.h add command -label {About...} -command help_about
.mb.h add separator
.mb.h add command -label {Do What I Mean} -command help_dwim
.mb add cascade -label {Help} -menu .mb.h
tracker::tracker .ta -rows 64 -cols 1 -width 80 -height 380\
-yscrollcommand {yset 1} -state readonly
.ta columnconfigure default -type numberhex -width 8
tracker::tracker .t -rows 64 -cols 16 -width 460 -height 380\
-yscrollcommand {yset 2} -selectionmethod text \
-selectionnotify update_sel -setdatanotify update_data -cursornotify update_cursor
.t columnconfigure default -type numberhex -width 2
tracker::tracker .tb -rows 64 -cols 16 -width 300 -height 380\
-yscrollcommand {yset 3} -selectionmethod text -state readonly
.tb columnconfigure default -type numberhex -displaymethod byte -width 1
scrollbar .vs -orient vertical -command {yview}
set row 0
grid .ta -row $row -column 0 -sticky news
grid .t -row $row -column 1 -sticky news
grid .tb -row $row -column 2 -sticky news
grid .vs -row $row -column 10 -sticky ns
grid columnconfigure . 0 -weight 1
grid rowconfigure . 0 -weight 1
incr row
grid [frame .f] -row $row -sticky news -columnspan 2
grid \
[label .f.l1 -text "Jump to offset:"] \
[spinbox .f.v1 -width 5 -from 0 -to 999999 -increment 1 -validate all] \
[label .f.l2 -text "Kb + "] \
[spinbox .f.v2 -width 5 -from 0 -to 1023 -increment 16 -wrap 1 -validate all] \
[label .f.l3 -text "bytes"] \
[button .f.b1 -text "Go!" -command {jump_to_offset [.f.v1 get] [.f.v2 get]}] \
[label .f.l4 -text ""] \
-row 2 -sticky news
grid columnconfigure .f 6 -weight 1