Book HomeMastering Perl/TkSearch this book

9.6. Creating Items in a Canvas

The whole point of having a Canvas is to put items in it. You can create arcs, bitmaps, images, lines, rectangles, ovals (circles), polygons, text, and widgets. Each has an associated createXXX method, where the type of item you want to create replaces the XXX. Each of the create methods returns a unique ID, which can be used to refer to the item later. When you see a method that takes a tag or an ID as an argument, the ID is the one returned from the create method.

9.6.1. The Arc Item

When you create an arc, you specify a bounding rectangle with two sets of x and y coordinates. The arc is drawn within the confines of the bounding box. The basic createArc statement is as follows:

$id = $canvas->createArc(x1, y1, x2, y2);

Any additional options used with createArc are specified after the coordinates:

$id = $canvas->createArc(x1, y1, x2, y2, option => value);

Each option for the arc item can be used later with the itemcget and itemconfigure Canvas methods. The options are:

-extent => degrees
The length of the arc is specified in degrees by using the -extent option. The default -extent (or length) is 90 degrees. The arc is drawn from the starting point (see -start option) counterclockwise within the rectangle defined by (x1, y1) and (x2, y2). The degrees value should be between -360 and 360. If it is more or less, the value used is the specified number of degrees modulo 360.

Here are some examples of the -extent option:

# This draws half of an oval
$canvas->createArc(0,0,100,150, -extent => 180);
# This will draw 3/4 of an oval
$canvas->createArc(0,0,100,150, -extent => 270);
-fill => color
To fill the arc with the specified color. By default, there is no fill color for an arc.

-outline => color
Normally the arc is drawn with a black outline. To change the default, use the -outline option. The outline color is separate from the fill color, so to make it a completely solid object, make the color for -outline and -fill the same.

-outlinestipple => bitmap
To use -outlinestipple, you must also use the -outline option. Normally the outline of the arc is drawn solid. Use a bitmap with -outlinestipple to make the outline nonsolid; the specified bitmap pattern will be used to draw the outline of the arc.

-start => degrees
The value associated with the -start option determines where Perl/Tk starts drawing the arc. The default start position is at three o'clock (0 degrees). The specified degrees are added to this position in a counterclockwise direction. Use -start => 90 to make the arc start at the twelve o'clock position, use -start => 180 to make the arc start at the nine o'clock position, and so on.

-stipple => bitmap
The -stipple option fills the arc with a bitmap pattern, but the -fill option must be specified as well.

-style => "pieslice" | "chord" | "arc"
The -style of the arc determines how the arc is drawn. The default, "pieslice", draws the arc and two lines from the center of the oval ends of the arc segment. The "chord" value draws the arc and a line connecting the two end points of the arc segment. The "arc" value draws just the arc portion with no other lines. The -fill and -stipple options are ignored if "arc" is used.

-tags => taglist
When you create an arc, you use the -tags option to assign tag names to it. The value associated with -tags is an anonymous array of tag names; for example:

$canvas->createArc(0,0,10,140,-tags => ["arc", "tall"]);

You don't need to use an anonymous array if you are only specifying one tag name:

$canvas->createArc(0,0,10,140,-tags => "arc");
-width => amount
This specifies the width of the outline. The default -width is 1.

9.6.2. The Bitmap Item

A Canvas widget can display a bitmap instead of text, just as a Button or Label can. You can use createBitmap to insert a bitmap into your Canvas widget:

$id = $canvas->createBitmap(x, y);

Of course, you must use the -bitmap option to specify which bitmap to display or you won't see anything. So we really create a bitmap like this:

$id = $canvas->createBitmap(x, y, -bitmap => bitmap);

The other options available for createBitmap are:

-anchor => "center" | "n" | "e" | "s" | "w" | "ne" | "nw" | "se" | "sw"
The -anchor option determines how the bitmap is placed on the Canvas relative to the (x, y) coordinates indicated. The default for -anchor is "center", which puts the center of the image at the (x, y) coordinates. Using a single cardinal direction (for example, "e") would place the center of that edge at the (x, y) coordinates.

-background => color
The -background option specifies the color to use for all the 0 (zero) bitmap pixels. If you don't specify a background color or use an empty string (""), the 0 pixels will be transparent.

-bitmap => bitmapname
You must use the -bitmap option to tell the Canvas which bitmap to display. You can use the built-in bitmaps (such as 'info' or 'warning') just as you can with the Button widget, or you can specify a filename. Remember, to specify a bitmap file, use an @ sign in front of the filename.

-foreground => color
The foreground color of a bitmap is the opposite of the background color. (By definition, bitmaps can have only two colors.) The -foreground option will color all the 1 pixels with this color. The default for -foreground is black.

-tags => taglist
Use the -tags option to assign tag names to a bitmap. The value associated with -tags is an anonymous list of tag names; for example:

$canvas->createBitmap(0,0, -bitmap => 'info', 
                      -tags => ["info", "bitmap"]);

You don't need to use the list if you are only specifying one tag name:

$canvas->createBitmap(0,0, -bitmap => 'info', -tags => "bitmap");

9.6.3. The Image Item

If we can create a bitmap on a Canvas, it makes sense that we can create an image as well. We can do so with the createImage method:

$id = $canvas->createImage(x, y, -image => image);

Again, you have to specify an image to display or you won't see anything. The other options available for createImage are:

-anchor => "center" | "n" | "e" | "s" | "w" | "ne" | "nw" | "se" | "sw"
The -anchor option for an image works the same as it does for a bitmap. The -anchor option is how the image is positioned around the (x, y) coordinates.

-image => $image
The -image option indicates which image to display. The image value is actually a reference to an image created with the Photo or Bitmap methods. (See Chapter 3, "Fonts" for more information on how to specify an image file.)

-tags => taglist
Use the -tags option to assign tag names to an image. The value associated with -tags is an anonymous list of tag names; for example:

$canvas->createImage(0,0, -image => $imgptr, 
                      -tags => ["image", "blue"]);

You don't need the list if you are specifying only one tag name:

$canvas->createImage(0,0, -image => $imgptr, -tags => "image");

9.6.4. The Line Item

The createLine method can actually create multiple connected lines, not just one. The first two coordinate sets you supply create the first line, and any additional coordinates will continue the line to that point:

$id = $canvas->createLine(0,0, 400,400);           # creates one line
$id = $canvas->createLine(0,0, 400,400, -50, 240); # creates two lines

After the coordinates, you can specify any options and values you wish to configure the line(s); the options and values are as follows:

-arrow => "none" | "first" | "last" | "both"
Use the -arrow option to place arrowheads at either end of the line (or both). If you have more than one line in your createLine method, only the first and/or last point can be made into an arrow. If you want each line to have an arrowhead, use multiple createLine statements.

-arrowshape => [ dist1, dist2, dist3 ]
The -arrowshape option applies only if you use the -arrow option as well.

Specify the three distances by using an anonymous list such as this:

$canvas->createLine(10, 10, 200, -40, -arrow => "both", 
                    -arrowshape => [ 20, 20, 20]);

Figure 9-4 shows what the distance values mean.

Figure 9-4

Figure 9-4. Definition of arrowhead

-capstyle => "butt" | "projecting" | "round"
Instead of arrowheads, you can make the ends of the line have one of these styles.

-fill => color
The -fill option is misnamed, because it isn't actually filling anything. The line is simply drawn with this color instead of black.

-joinstyle => "bevel" | "miter" | "round"
The -joinstyle option affects how multiple lines are joined together. If there is only one line created, this option has no effect.

-smooth => 1 | 0
If -smooth has a value of 1, then, using Bezier spline(s), the line(s) will be drawn as a curve. The first two lines make the first spline, the second and third line make up the second spline, and so on. To make a straight line, repeat the end points of the desired straight line (or use createLine again to make a separate line).

-splinesteps => count
When you use the -smooth option, the more -splinesteps you use, the smoother the curve. To find out how many steps create the desired effect, you'll have to experiment with different values.

-stipple => bitmap
To have the line drawn with a bitmap pattern (1 values in the bitmap have color; 0 values are transparent), use the -stipple option. The bitmap can be a default bitmap name or a filename. The wider the line (see -width), the more the stipple design will show up.

-tags => taglist
When you create a line (or lines), assign tag names to them using the -tags option. The value associated with -tags is an anonymous list of tag names; for example:

$canvas->createLine(0,0, 100,100, -tags => ["line", "blue"]);

You don't need to use a list if you are specifying only one tag name:

$canvas->createLine(0,0, 100, 100, -tags =>
"line");
-width => amount
You can use the -width option to make the line(s) thicker. Normally the line is drawn only 1 pixel wide. The amount can be any valid screen distance (e.g., centimeters, inches).

9.6.5. The Oval Item

An oval can be a circle if you draw it just right. To create a circle or oval, use the createOval method and specify two sets of points that indicate a rectangle (or square) in which to draw the oval. Here is a simple example:

$id = $canvas->createOval(0,0, 50, 50);  # creates a circle
$id = $canvas->createOval(0,0, 50, 100); # creates an oval

The options for the oval will be familiar, so we'll just cover them briefly:

-fill => color
Fills in the oval with the specified color. This color is different than the outline color. By default, the oval is not filled.

-outline => color
The outline is the line drawn around the outside of the circle. Normally, the outline is black, but you can use the -outline option to change it. If you make the outline and the fill color the same, the oval appears solid.

-stipple => bitmap
To fill the oval with a bitmap pattern (1 values in the bitmap are colored; 0 values are transparent), use the -stipple option. If the -fill option isn't used, -stipple has no effect. -stipple takes a default bitmap name or a file with a bitmap in it.

-tags => taglist
When you create an oval, use the -tags option to assign tag names to it. The value associated with -tags is an anonymous list of tag names; for example:

$canvas->createOval(0,0, 100,100, -tags => ["oval", "blue"]);

You don't need to use a list if you are specifying only one tag name:

$canvas->createOval(0,0, 100, 100, -tags => "oval");
-width => amount
The -width option changes how wide the outline of the oval is drawn. The default for -width is 1 pixel.

9.6.6. The Polygon Item

A polygon is merely a bunch of lines where the first point is connected to the last point automatically to create an enclosed area. The createPolygon method requires at least three (x, y) coordinate pairs. For instance, the following piece of code will create a three-sided polygon:

$id = $canvas->createPolygon(1000,1000, 850,950, 30,40);

Additional (x, y) coordinate pairs can be specified as well; for example:

$id = $canvas->createPolygon(1000,1000, 850,950, 30,40, 500,500);

The options you can specify with createPolygon are the same as those you use with createLine: -fill, -outline, -smooth, -splinesteps, -stipple, -tags, and -width. Just remember that createPolygon connects the first point to the last point to enclose the area.

9.6.7. The Rectangle Item

As if being able to create a rectangle using createLine or createPolygon weren't enough, we also have the createRectangle method. It only takes two (x, y) coordinate sets, which are the opposite corners of the rectangular area:

$id = $canvas->createRectangle(10, 10, 50, 150);

Again, we have seen the options available for createRectangle with the other create methods: -fill, -outline, -stipple, -tags, and -width. Although we've covered these options already, here are a few examples:

# A blue rectangle with black outline:
$canvas->createRectangle(10,10, 50, 150, -fill => 'blue');
# A blue rectangle with a thicker outline:
$canvas->createRectangle(10,10, 50, 150, -fill => 'blue', -width => 10);

9.6.8. The Text Item

Finally, an item type that doesn't have lines in it! You can use the createText method to add text to a Canvas widget. It requires an (x, y) coordinate pair, which determines where you place the text in the Canvas and the text to be displayed:

$id = $canvas->createText(0,0, -text => "origin");

The -text option is actually optional, but then you wouldn't see any text on the screen. Because there is no point in that, we will assume that you will always specify -text with a text value to display. The other options available for text items are as follows:

-anchor => "center" | "n" | "e" | "s" | "w" | "ne" | "nw" | "se" | "sw"
The -anchor option determines where the text is placed in relation to the (x, y) coordinate. The default is centered: the text will be centered over that point no matter how large the piece of text is.

-fill => color
The text is normally drawn in black; you can use the -fill option to change this. The name of this option doesn't make much sense when you think about it in terms of text (normally our widgets use -foreground to change the color of the text). For example, -fill => 'blue' will draw blue text.

-font => fontname
You can change the font for the displayed text by using the -font option.

-justify => "left" | "right" | "center"
If the displayed text has more than one line, the -justify option will cause it to be justified as specified.

-stipple => bitmap
This option is a bit strange, but here it is anyway. If you specify a bitmap name (or file) with the -stipple option, the text will be drawn by using the bitmap pattern. Most of the time, this will make the text unreadable, so don't use it unless you're using a large font.

-tags => taglist
The taglist is a single tag name or an anonymous list of tag names to be assigned to the item.

-text => string
This is not optional. The specified string is displayed in the Canvas widget at the (x, y) coordinate.

-width => amount
This is another misnamed option, because it does not change the width of each text character. It determines the maximum length of each line of text. If the text is longer than this length, the line will automatically wrap to a second line. The default value for amount is 0, which will break lines only at newline characters. Lines are always broken at spaces so words won't be cut in half.

The following options, discussed earlier, work the same as they would for an Entry widget or a Text widget: -insertbackground, -insertborderwidth, -insertofftime, -insertontime, -insertwidth, -selectbackground,-selectborderwidth, and-selectforeground. See Chapter 5, "Label and Entry Widgets" and Chapter 8, "The Text, TextUndo,and ROText Widgets" for more details.

9.6.8.1. Text item indexes

Methods that affect text items will sometimes ask for an index value. Text indexes for the regular Text widget were covered in Chapter 8, "The Text, TextUndo,and ROText Widgets", and the index values for a Canvas text item are similar. The only difference is that each item is considered only one line (even if it has "\n" characters in it). Index values are as follows:

n
A number value. For example, 0 or 12. 0 is the first character, 1 is the second, and so on.

"end"
The character directly after the last one. Often used with the insert method to add to the end of the string.

"insert"
The character directly before the insertion cursor.

"sel.first"
The first character of the selected text. Only valid if there is a selection.

"sel.last"
The last character of the selected text. Only valid if there is a selection.

"@x,y"
The character closest to the point (x, y) of the Canvas (not screen coordinates).

9.6.8.2. Deleting characters

To delete characters from within a text item, use the dchars method: $canvas->dchars(tag/id, first [, last ]). Specify a tag or ID to match the text item(s) and the index at which to start deleting. If the end index isn't specified, all the characters to the end of the string will be deleted (including any "\n" characters).

9.6.8.3. Positioning the cursor

To specifically place the blinking text cursor, use the icursor method : $canvas->icursor(tag/id, index). The cursor will only show up immediately if the specified item has the current keyboard focus. You can still set the position of the cursor if it doesn't, it just won't display until the item does get the keyboard focus.

9.6.8.4. Index information

To find an index based on another index, use the index method. Here's an example:

$index = $canvas->index("textitem", "sel.first");

This returns the numerical index associated with the first selected character in the text item. If more than one item matches the tag or ID indicated (in this case, it's a tag named "textitem"), then the first one found is used.

9.6.8.5. Adding text

To add more text to a text item, use the insert method: $canvas->insert(tag/id, index, string). The first argument is the tag or ID, which can match multiple items. The second argument is the index before which to insert the new string, and the last argument is the actual string to insert into the text item.

9.6.8.6. Selecting text

There are several methods you can use to programmatically select portions of the text. To clear the selection (any selection; there are no tags or IDs sent with this command), use $canvas->selectClear. To select a portion of text, use selectFrom and selectTo. The following two lines of code select the text from beginning to end for the first item that matches the tag "texttag":

$canvas->selectFrom("texttag", 0);
$canvas->selectTo("texttag", "end");

You can use the selectAdjust method to add to the selection: $canvas->selectAdjust("adjust", tag/id, index). To get the ID of the item that currently has the selection in it, use $id = $canvas->selectItem.

9.6.9. The Widget Item

You can put any type of widget inside a Canvas—Buttons, Checkbuttons, Text widgets, or even another Canvas widget (if you are a little crazy)—by using the createWindow method. Before calling createWindow, you must create the widget to put into the Canvas. Here's an example:

$bttn = $canvas->Button(-text => "Button", 
                        -command => sub { print "Button in Canvas\n"; });
$id = $canvas->createWindow(0, 0, -window => $bttn);

There are a few things you should note about this example (which is fairly typical, except the subroutine associated with the Button doesn't do anything useful):

The following options, which you can use when you call createWindow, are more like options you use with pack than widget options:

-anchor => "center" | "n" | "e" | "s" | "w" | "ne" | "nw" | "se" | "sw"
The widget will be placed at the (x, y) coordinates according to the -anchor value. The default is "center", which means that the widget will have its center point placed on (x, y).

-height => amount
The widget will be given this height. If you don't use -height, the widget will have the height it was created with (usually the natural size of the widget).

-tags => taglist
The taglist associates a tag with the widget. You can specify either a single tag string or an anonymous list of tag names.

-width => amount
The widget will be given this width. If you don't use the -width option, the widget will have the width it was created with (the natural size of the widget).

-window => $widget
This is a nonoptional option. If you don't specify -window, there will be no widget put in the Canvas. The $widget is a reference to a widget item. You can create the widget beforehand or inline as follows:

$canvas->createWindow(0,0, -window => $canvas->Button(-text => "Button", 
         -command => sub { print "Button!\"; }));

It makes sense to create the widget inline if you don't need to do anything fancy with it.

9.6.10. The Grid Item

Perl/Tk has an experimental grid item type that displays dotted, dashed, or solid lines, in both the x and y dimensions. The effect is reminiscent of old-fashioned graph paper.

Grid items cover the entire Canvas, but never enclose or overlap any area and are not near any point, so you cannot search for them using the closest, enclosed, or overlapping attributes. In most other regards, they behave like other Canvas item types. Currently, grids, like window items, do not appear in PostScript output.

Grid items are created like this:

 $canvas->createGrid(x1, y1, x2, y2, ... );

x1 and y1 specify the origin of the basal grid cell, and x2 and y2 specify its width and height, respectively; the cell is replicated over the entire surface of the Canvas widget. By default, dots are drawn at every grid intersection, unless the -lines option is set true. When drawing lines, dash specifications are honored.

This code generated Figure 9-5:

my $c = $mw->Canvas(qw/-width 300 -height 200/)->grid;
$c->configure("-scrollregion" => [0,0, 300, 200]);

$c->createGrid(0, 0, 10, 10);
$c->createGrid(0, 0, 50, 50, -lines => 1, -dash => '-.');
$c->createGrid(0, 0, 100, 100, -width => 3, -lines => 1);

One important note: grid items remain invisible unless a scroll region is defined. This may be construed as a bug, which is one reason why grids are deemed experimental.

Figure 9-5

Figure 9-5. A canvas with three grid items

9.6.11. The Group Item

Perl/Tk sports a new Canvas item called a group. A group item is actually a collection of standard Canvas items that can be manipulated simultaneously. The following code creates an oval and a rectangle, then groups them together:

$one = $canvas->createOval(5,  0, 20, 30, -fill => 'blue');
$two = $canvas->createRectangle(0, 20, 50, 75, -fill => 'red');
$group = $canvas->createGroup([0, 0], -members => [$one, $two]);
$mw->update;
$mw->after(1000);
$canvas->move($group, 100, 100);

Figure 9-6 shows the outcome.

Figure 9-6

Figure 9-6. Before move

After a one-second delay, the group is moved to a new Canvas coordinate, shown in Figure 9-7.

Figure 9-7

Figure 9-7. After move

Of course, sometimes you want to get to individual items within the group, perhaps to configure a special attribute. The current idiom is to iterate through the members of the group, like this:

foreach my $member ($canvas->itemcget($group, -members)) {
    print "member=$member\n";
}

This example prints out the item ID for each member of the group, but you can use the item IDs in an itemconfigure call.



Library Navigation Links

Copyright © 2002 O'Reilly & Associates. All rights reserved.