editwindow

Editwin is a simple package that adds a toplevel edit entry to a widget. You can use it for example to change the value of a label.

The entry can be canceled with Escape or clicking anywhere in the containing toplevel. Confirmed your edit with Return.

# ------------------------------------------------------------------------
# editwin, version 0.2
# a simple toplevel entry bound to a widget and a variable
#
# Copyright (c) 2009 Uwe Koloska, voice INTER connect GmbH
# ------------------------------------------------------------------------
#
# This library is free software; you can use, modify, and redistribute it
# for any purpose, provided that existing copyright notices are retained
# in all copies and that this notice is included verbatim in any
# distributions.
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# ------------------------------------------------------------------------

package require Tk 8.5

namespace eval editwin {
    namespace export editwin
}

proc editwin::editwin {w var args} {
    variable {}

    array set opts {
        -validatecommand ""
        -width 20
    }
    array set opts $args

    set ($w,var) $var
    set ($w,validate) $opts(-validatecommand)
    set ($w,width) $opts(-width)
    bind $w <Double-ButtonPress-1> [namespace code [list _do $w]]
}

proc editwin::_do {w args} {
    variable {}

    set var $($w,var)
    set tl [winfo toplevel $w]
    if {$tl eq "."} {
        set ewin .edit
    } else {
        set ewin $tl.edit
    }
    set ewinRoot $ewin
    set num 0
    while {[winfo exists $ewin]} {
        incr num
        set ewin ${ewinRoot}$num
    }
    unset ewinRoot num

    set ($w,widget) $ewin
    catch {destroy $ewin}
    set ($w,value) [set $var]
    ttk::entry $ewin -textvariable [namespace current]::($w,value) -width $($w,width)
    if {$($w,validate) ne ""} {
        $ewin configure  -validate key -validatecommand $($w,validate)
    }

    set x [expr {[winfo rootx $w] - [winfo rootx $tl]}]
    set y [expr {[winfo rooty $w] + [winfo height $w] - [winfo rooty $tl]}]

    place $ewin -x $x -y $y
    $ewin selection range 0 end
    bind $ewin <Escape> [namespace code [list _end $w]]
    bind $ewin <Return> [namespace code [list _set $w]]
    set ($w,bpCallback) [bind $tl <ButtonPress>]
    bind $tl <ButtonPress> [namespace code [list _end $w]]
    focus $ewin
}

proc editwin::_set {w} {
    variable {}

    set $($w,var) $($w,value)
    _end $w
}

proc editwin::_end {w} {
    variable {}

    destroy $($w,widget)
    bind [winfo toplevel $w] <ButtonPress> $($w,bpCallback)
    set ($w,bpCallback) {}
}

And here an overly complex demo app that had shown a problem with the focus -- this was fixed in 0.2.

#! /usr/bin/env tclkit8.5

package require Tk 8.5

set scriptdir [file dirname [info script]]
source [file join $scriptdir editwin.tcl]

set __oldFocus ""
proc showFocus {} {
    set focus [focus]
    if {$focus ne $::__oldFocus} {
        set last [focus -lastfor .]
        puts "focus = '$focus' (last = '$last')"
        set ::__oldFocus $focus
    }
    after 1000 showFocus
}

proc validateMynum {value} {
    if {$value eq "+" || [string length $value] == 0} {
        set result 1
    } elseif {[string is double $value]} {
        set result [expr {$value > 0.0 && $value < 30.0}]
    } else {
        set result 0
    }
    return $result
}

set validatecommand {validateMynum %P}
ttk::label .edit -textvariable mynum -background lightgreen -width 5
editwin::editwin .edit ::mynum -validatecommand $validatecommand -width 5

ttk::button .b1 -text "Button 1"
ttk::button .b2 -text "Button 2"
ttk::entry  .e1 -textvariable myentry

pack .b1 .e1 .edit .b2 -side top -padx 64 -pady 32

set mynum 31.2
set myentry "some text"
showFocus

2009-11-06 UKo: v0.1 first version that needs a focus fix on linux (tested with 8.5.7) 2009-12-07 UKo: v0.2 the version that fixes this nasty focus bug