Restricting the Movement of Canvas Items

WJG (21 January 2005) Sometimes the most simplest of tasks can be frustrating. For me, restricting the movement of canvas items was one of these niggly little things. Much of the code we see here on the Wiki gives advice and on how to get things moving but little nothing about stopping the little buggers becoming dragged out of the canvas view.

 package require Tk
 #-------
 # movement handler
 #-------
 proc drag.canvas.item {canWin item newX newY} {
     set xDiff [expr {$newX - $::x}]
     set yDiff [expr {$newY - $::y}]
     #test before moving
     if {[inside $canWin $item $xDiff $yDiff]} {
         puts inside
         $canWin move $item $xDiff $yDiff
     }  
     set ::x $newX
     set ::y $newY
 }
 #-------
 # test to see if the new position is outside the canvas viewport
 #-------
 proc inside {w item xDiff yDiff} {
     #canvas extents
     set can(minx) -1
     set can(miny) -1
     set can(maxx) [winfo width $w ]
     set can(maxy) [winfo height $w ]
     #item coords
     set item [$w coords $item]  
     #check min values
     foreach {x y} $item {
         set x [expr $x + $xDiff]
         set y [expr $y + $yDiff]       
         if {$x < $can(minx)} {
             return 0
         }
         if {$y < $can(miny)} {
             return 0
         }
         if {$x > $can(maxx)} {
             return 0
         }
         if {$y > $can(maxy)} {
             return 0
         }
     }
     #puts $item
     return 1
 } 
 #-------
 # test it
 #-------
 pack [canvas .c -bg white] -expand 1 -fill both
 button .b -text "Test Button"
 .c create rectangle 0 0 100 100 -fill  red -tag tag
 .c bind tag <1> {
     set ::x %X
     set ::y %Y
 }
 .c bind tag <B1-Motion> [list drag.canvas.item .c tag %X %Y]

Category GUI Category Widget