In place edit

In place edit

(This is my first page on the Wiki, so please forgive me if I make some mistake.)

I'm experimenting in Tcl/Tk some ui concepts often found in applications out there. The one I'm showing you this time is what I called "in place edit": a (sort of) widget linked to another one which you can use to change a value of the latter without opening dialog boxes. To be practical, this could be a sample use of the IPE (In Place Edit):

  1. you bind the IPE to a label event;
  2. when the event is fired, a special entry widget appears, showing the text of the label;
  3. you change the text as you wish;
  4. if you hit Esc, or click somewhere out of the IPE, or change the keyboard focus, the IPE disappears and nothing happens;
  5. otherwise, if you hit Enter (currently, not on the numeric pad), your changes are committed and the label text is modified.

Please note that this is a (simple) experiment and not production ready code. Moreover, I'm testing the code on Linux and fixing it for that system (however, it seems to work on Windows, too).

First, let's see some pictures of the code in action!

Here, I change the text of a label, by double-clicking on it, editing it, and finally hitting Enter.

Here, I do the same with a button, but double-right-clicking on it!

Finally, let's see how the code works with toplevel captions too (by double-clicking on the toplevel empty area):

Now, this is the code I used: it contains both the code for the IPE and that for the usage samples.

namespace eval ipe {
    variable ipe
    variable tl
    variable tlbtnbind
    variable outvar

proc ipe::init {} {
    variable ipe

    set ipe [toplevel .ipe]
    wm withdraw $ipe
    wm protocol $ipe WM_DELETE_WINDOW ipe::hide
    wm attributes .ipe -topmost 1
    wm overrideredirect .ipe 1

    ttk::frame $ipe.f
    pack $ipe.f

    ttk::entry $ipe.f.e
    pack $ipe.f.e

    bind $ipe.f.e <Return> [list ipe::hide 1]
    bind $ipe.f.e <Escape> ipe::hide
    bind $ipe.f <FocusOut> ipe::hide

proc ipe::hide {{store 0}} {
    variable ipe
    variable outvar
    variable tl
    variable tlbtnbind

    bind $tl <Button> $tlbtnbind
    wm withdraw $ipe

    if { $store } {
        uplevel #0 set $outvar [list [$ipe.f.e get]]

proc ipe::show {w txt outName} {
    variable ipe
    variable tl
    variable tlbtnbind
    variable outvar

    set outvar $outName
    set tl [winfo toplevel $w]
    set tlbtnbind [bind $tl <Button>]

    bind $tl <Button> ipe::hide

    $ipe.f.e delete 0 end
    $ipe.f.e insert 0 $txt

    wm deiconify $ipe
    wm geometry $ipe =+[winfo rootx $w]+[winfo rooty $w]
    focus $ipe.f.e

# Samples
ttk::style theme use clam

set labelvar "Testo"
ttk::label .l -textvar labelvar
pack .l

set buttonvar "Pulsante"
ttk::button .b -textvariable buttonvar
pack .b

ttk::entry .e
pack .e

proc tlcaption {name null op} {
    upvar #0 $name tlvar
    wm title .t $tlvar
toplevel .t
trace add variable tlvar write tlcaption
set tlvar "Finestra"


bind .l <Double-1> {ipe::show %W $labelvar labelvar; break}
bind .b <Double-3> {ipe::show %W $buttonvar buttonvar; break}
bind .t <Double-1> {ipe::show %W $tlvar tlvar; break}

The code above is really straightforward; I'm using Ttk widgets, but it seems to work with old fashioned Tk widgets, too.

(I posted a longer article about this experiment on my just created blog; you can also go there, if you like, but it is in italian: )

MarcoP (30 jul 2012): fixed broken image links; I changed my blog, reposted the article with the images and edited the links here.

RLE (2012-07-30): You can also achieve a similar effect using the place geometry manager to place your edit widget above the widget it is supposed to sit on top of. One advantage of using place is you avoid having to position a toplevel and thereby hope that the OS window manager obliges properly.

MarcoP (31 jul 2012): you are right, using the place geometry manager is another option; one (little) advantage of the toplevel is it becomes indepentent of the position of your application toplevel, so that you can always make it visible, even if the space in your application is too small.