www.gibmonks.com

  Previous section   Next section

Practical Programming in Tcl & Tk, Third Edition
By Brent B. Welch

Table of Contents
Chapter 34.  The Canvas Widget


Hello, World!

Example 34-2 creates an object that you can drag around with the mouse. It introduces the use of tags to classify objects. In this case the movable tag gets bindings that let you drag the item, so any item with the movable tag shares this behavior. The example uses Scrolled_Canvas from Example 34-1. When you use a scrolled canvas, you must map from the view coordinates reported by bindings to the canvas coordinates used to locate objects:

Example 34-2 The canvas "Hello, World!" example.
proc CanvasHello {} {
   set can [Scrolled_Canvas .c -width 400 -height 100 \
      -scrollregion {0 0 800 400}]
   pack .c -fill both -expand true
   # Create a text object on the canvas
   $can create text 50 50 -text "Hello, World!" -tag movable
   # Bind actions to objects with the movable tag
   $can bind movable <Button-1> {CanvasMark %x %y %W}
   $can bind movable <B1-Motion> {CanvasDrag %x %y %W}
}
proc CanvasMark {x y can} {
   global canvas
   # Map from view coordinates to canvas coordinates
   set x [$can canvasx $x]
   set y [$can canvasy $y]
   # Remember the object and its location
   set canvas($can,obj) [$can find closest $x $y]
   set canvas($can,x) $x
   set canvas($can,y) $y
}
proc CanvasDrag {x y can} {
   global canvas
   # Map from view coordinates to canvas coordinates
   set x [$can canvasx $x]
   set y [$can canvasy $y]
   # Move the current object
   set dx [expr $x - $canvas($can,x)]
   set dy [expr $y - $canvas($can,y)]
   $can move $canvas($can,obj) $dx $dy
   set canvas($can,x) $x
   set canvas($can,y) $y
}

Example 34-2 creates a text object and gives it a tag named movable:

.c create text 50 50 -text "Hello, World!" -tag movable

The first argument after create specifies the type, and the remaining arguments depend on the type of object being created. Each canvas object requires some coordinates, optionally followed by attribute value pairs. The complete set of attributes for canvas objects are presented later in this chapter. A text object needs two coordinates for its location.

Canvas Tags

The create operation returns an ID for the object being created, which would have been 1 in this case. However, the code manipulates the canvas objects by specifying a tag instead of an object ID. A tag is a more general handle on canvas objects. Many objects can have the same tag, and an object can have more than one tag. You can define bindings on tags, and you can define attributes for tags that will be picked up by objects with those tags.

A tag name can be almost any string, but you should avoid spaces that can cause parsing problems and pure numbers that get confused with object IDs. There are two predefined tags: current and all. The current tag applies to whatever object is under the mouse. The all tag applies to all the objects on the canvas.

The example defines behavior for objects with the movable tag. Pressing button 1 starts a drag, and dragging with the mouse button down moves the object. The pathname of the canvas (%W) is passed to CanvasMark and CanvasDrag so these procedures can be used on different canvases. The %x and %y keywords get substituted with the X and Y coordinate of the event:

$can bind movable <Button-1> {CanvasMark %x %y %W}
$can bind movable <B1-Motion> {CanvasDrag %x %y %W}

The CanvasMark and CanvasDrag procedures let you drag the object around the canvas. Because CanvasMark is applied to any object with the movable tag, it must first find the object that was clicked on. First, the view coordinates are mapped into the canvas coordinates with the canvasx and canvasy operations:

set x [$can canvasx x]
set y [$can canvasy y]

Once you do this, you can use the find operation:

set canvas($can,obj) [$can find closest $x $y]

The actual moving is done in CanvasDrag with the move operation:

$can move $canvas($can,obj) $dx $dy

Try creating a few other object types and dragging them around, too:

$can create rect 10 10 30 30 -fill red -tag movable
$can create line 1 1 40 40 90 60 -width 2 -tag movable
$can create poly 1 1 40 40 90 60 -fill blue -tag movable

The CanvasMark and CanvasDrag procedures can be used with any canvas. They use the global array canvas to keep their state, and they parameterize the indices with the canvas pathname to avoid conflict if there is more that one canvas in the application. If you get into this coding habit early, then you will find it easy to write reusable code.

graphics/tip_icon.gif

Canvas tags are not persistent.


Canvas tags do not work exactly like tags in the text widget. In the text widget, a tag is completely independent of the text. You can configure a text tag before it is applied to text, and the tag configuration is remembered even if you remove it from the text. A canvas tag, in contrast, must be applied to an object before you can configure it. If you configure a canvas tag that is not applied to any objects, those settings are forgotten. If you remove all the objects that share a tag, any settings associated with those tags are forgotten.


      Previous section   Next section
    Top