Richard Suchenwirth 2002-02-26: I needed to mark an axis-parallel rectangle on a [canvas] by drawing it with the mouse pointer. This is a simplified task compared to Canvas item selections, but the solution could also be done simpler, with a single [bind] proc (which dispatches according to event type), and no global variable required.
In the binding for the <ButtonRelease-1> registration, you specify a "callback": a command name or prefix, to which will be appended a list consisting of the coordinates of the marked rectangle {x0 y0 x1 y1}, and which will then be executed in global scope, as is necessary for bindings:
proc canvas'rect {w x y type {cmd ""}} { set x [$w canvasx $x] set y [$w canvasy $y] switch -- $type { press { $w delete rect $w create rect $x $y $x $y -tag rect } motion { set item [$w find withtag rect] foreach {x0 y0 x1 y1} [$w coords $item] break $w coords $item $x0 $y0 $x $y } release { uplevel \#0 [lappend cmd [$w coords [$w find withtag rect]]] } default {error "bad type $type: use press, motion, or release"} } } # Usage example and demo: if {[file tail [info script]] == [file tail $argv0]} { pack [canvas .c] bind .c <1> {canvas'rect %W %x %y press} bind .c <B1-Motion> {canvas'rect %W %x %y motion} bind .c <ButtonRelease-1> {canvas'rect %W %x %y release "diag %W"} proc diag {w coords} { foreach {x0 y0 x1 y1} $coords break $w create line $x0 $y0 $x1 $y1 -fill green -width 3 $w create line $x1 $y0 $x0 $y1 -fill red -width 3 } }
MGS: Here's a slightly modified version that allows you to draw rectangles in any direction:
proc canvas'rect {w x y type {cmd ""}} { upvar #0 $w _ set x [$w canvasx $x] set y [$w canvasy $y] switch -- $type { motion { if { $x < $_(x) } { set x1 $x ; set x2 $_(x) } else { set x1 $_(x) ; set x2 $x } if { $y < $_(y) } { set y1 $y ; set y2 $_(y) } else { set y1 $_(y) ; set y2 $y } $w coords rect $x1 $y1 $x2 $y2 } press { set _(x) $x set _(y) $y $w delete rect $w create rect $x $y $x $y -tag rect } release { unset _(x) unset _(y) uplevel #0 [concat $cmd [$w coords rect]] $w delete rect } default { error "bad type \"$type\": must be motion, press, or release" } } } # Usage example and demo: if { [info exists argv0] && [string equal [info script] $argv0] } { pack [canvas .c] bind .c <ButtonPress-1> {canvas'rect %W %x %y press} bind .c <B1-Motion> {canvas'rect %W %x %y motion} bind .c <ButtonRelease-1> {canvas'rect %W %x %y release "diag %W"} proc diag {c x1 y1 x2 y2} { $c create rect $x1 $y1 $x2 $y2 $c create line $x1 $y1 $x2 $y2 -fill green -width 3 $c create line $x2 $y1 $x1 $y2 -fill red -width 3 } }
sheila: 2004-10-27: I was playing around with this on my PC and on my mac. I added a stipple effect to grey out the portion of the image I had added to the canvas. Here is how I changed the code to do this.
release { # done, remove the saved coords unset _(x) unset _(y) set r [eval $w create rect [$w coords rect]\ -tag exclude -fill gray25 -stipple gray25] $w delete rect }
aside: I was curious about why you guys used the separate proc instead of just putting it in the release branch, so I put it in the release branch to see how it would work.
Anyway, this works like I thought it would on my PC, but on my mac the stipple looks solid. Everything seems slower on my mac as well. I was wondering what I did wrong? My mac is running panther, and I have the latest TkAquaBI on it (I updated it last night just to be sure).
gold added pix and some categories.
Ref. links Canvas,Canvas lasso selection