home | O'Reilly's CD bookshelfs | FreeBSD | Linux | Cisco | Cisco Exam  

Book HomeMastering Perl/TkSearch this book

8.5. Text Tags

Text tags give you another way to address portions of text in the Text widget. A tag has three purposes, and the same tag can serve all three or only one:

  • Assigning formatting information to a portion (or portions) of text

  • Associating a binding with text in the widget

  • Managing selected text

Tags can change how the text appears on the screen; font, size, coloring, and spacing are a few of the text properties affected by tags. You change text properties by creating your own tags (with their own names) and using option/value pairs to assign formatting information. In addition to changing the formatting, you can use a tag to apply a specific binding (such as perform a task when the user double-clicks on that text). A special tag, "sel", manages the selected text. Any time the user selects some text, the location of that text is marked with the "sel" tag.

Any of the text within the Text widget can have one or more tags associated with it. If you apply two tags to the same piece of text and they both alter the font, the last tag applied wins.

8.5.1. Tag Options

The options you can use to configure tagged text are mostly a subset of the configuration options of the Text widget itself. The configuration options for the Text widget are the defaults for all text in the Text widget. Using a tag allows you to change that formatting or binding on a case-by-case basis. There are some options that can be used only through tagged text.

-background => color
Sets the color of the area behind the text.

-bgstipple => pattern
Sets the pattern used to draw the area behind the text. Can create a shaded look.

-borderwidth => amount
Sets the width of the relief drawn around the edges of the text, line by line.

-data => scalar
Associates scalar with a tag, which allows you to store any amount of information for the tag. It can, of course, be a reference.

-elide => boolean
If boolean is true, text covered by the tag is not displayed.

-fgstipple => pattern
Sets the pattern used to draw the text.

-font => fontname
Sets the font used for the text.

-foreground => color
Sets the color of the text.

-justify => 'left' | 'right' | 'center'
Sets the position of the text within the Text widget.

-lmargin1=> amount
Sets the amount of indentation from the left edge for the first line of a paragraph.

-lmargin2=> amount
Sets the amount of indentation from the left edge for the second and greater lines of a paragraph. Sometimes called a hanging indent.

-offset => amount
Sets the amount the text is raised or lowered from the baseline. Can be used to create superscripts and subscripts.

-overstrike => 0 | 1
If a true value, causes the text to have a line drawn through it.

-relief => 'flat' | 'groove' | 'raised' | 'ridge' | 'sunken'
Determines the way the edges of the text are drawn, line by line.

-rmargin => amount
Sets the amount of space left between the text and the right edge of the widget.

-spacing1 => amount
Sets the amount of additional space left on top of a line of text that begins on its own line. Default is 0.

-spacing2 => amount
Sets the amount of additional space left on top of a line of text after it has been wrapped around automatically by the Text widget. Default is 0.

-spacing3 => amount
Sets the amount of additional space left after a line of text has been ended by a "\n". Default is 0.

-state =>'normal' | 'hidden'
Text is normally visible, but you may hide it if desired.

-tabs => list
Indicates the set of tab stops for this text. See Section 8.2.5, "Tab Stops" earlier in this chapter for more detailed information.

-underline => boolean
Indicates that the text should be drawn with an underline.

-wrap => 'none' | 'char' | 'word'
Determines the mode in which the text is wrapped. 'none' means lines that are longer than the Text widget is wide are not wrapped. 'char' will wrap at each character. 'word' will wrap between words.

8.5.2. A Simple Tag Example

Let's look at an example of how a simple tag is created and use it to insert some text into a Text widget (the resulting screen is shown in Figure 8-4):

$t = $mw->Text()->pack( );
$t->tagConfigure('bold', -font => "Courier 24 bold");
$t->insert('end', "This is some normal text\n");
$t->insert('end', "This is some bold text\n", 'bold');

Line 1 creates the Text widget and places it on the screen.

Line 2 creates the 'bold' tag. Don't be fooled by the use of the word "configure" instead of "create." When you configure a tag, you are creating it. We created a tag named 'bold' and associated a different font with it (it happens to be the same as our Unix Text widget default font, just the bold version).

At this point, we haven't changed anything in the Text widget. We are just setting up to use the tag later in the code. You can use any name to indicate a tag as long as it is a valid text string. We could have named the tag "bold_font" or "big_bold_font" or "tag1". If you have good programming style (and want to be able to maintain your code), use a name that indicates what the tag does.

Line 3 inserts some text into the Text widget using the default formatting.

Line 4 inserts some more text into the Text widget but uses the 'bold' tag. The insert method allows us to specify a tag as the third argument. This causes that string of text to be inserted into the Text widget and assigned the tag 'bold'. The 'bold' tag was configured to change the font, so any text with the 'bold' tag will be shown with the different font.

Figure 8-4

Figure 8-4. Text widget with normal and bold text

This is a pretty simplified example. What if we want to alter text that has been typed in by the user? We can't use the insert method then. We use the tagAdd method specifying a range of indexes to apply the tag to:

$t->tagAdd('bold', '1.0', 'end');

This applies the 'bold' tag to all the text within the Text widget.

8.5.3. Selections in a Text Widget Using the "sel" Tag

The "sel" tag is a special tag maintained by the Text widget. Any text the user selects will be assigned the "sel" tag. Unfortunately, there are no easy methods provided that help you determine if there is a selection or where it's located. Here are a few of the basic things you'll want to do with the selection.

To determine if the selection exists:

$if ($t->tagRanges('sel')) {
   ... do something with sel as an index ...

You may want to force the selection programmatically by using some of the tag methods (which we haven't covered yet) to put the "sel" tag on some text. For instance, to add the third line to the selected text:

$t->tagAdd('sel', '3.0', '3.0 lineend');

You can have multiple selections in the Text widget, and each time you call tagAdd, you're adding to the selection.

Here's an example that shows how to add another tag to the currently selected text:

$t->tagAdd('bold', 'sel.first', 'sel.last') if ($t->tagRanges('sel'));

When you use the "sel" tag as part of an index, you need to make sure the tag exists (using tagRanges) within the Text widget first or you'll get a really nasty error.

Here are two ways to get the currently selected text:

# Harder way:
$s1 = $t->get('sel.first', 'sel.last') if ($t->tagRanges('sel'));
# Easier way ($s2 is always set to something):
$s2 = $t->getSelected( );

The getSelected method is a convenience method for the Perl/Tk version of the Text widget. Look towards the end of this chapter in Section 8.19, "The Perl/Tk Text Widget Extended Methods" for more selection convenience methods.

8.5.4. Configuring and Creating Tags

The first thing you'll do with a tag is create it by using tagConfigure (unless you're using the automatically defined "sel" tag). The first argument to tagConfigure is the name of the tag. The rest of the arguments (which are optional) are option/value pairs, as described earlier in Section 8.5.1, "Tag Options". Here are some examples:

# creating a tag with no options
# Creating a tag that will change the color
$text->tagConfigure("blue", -foreground => "blue");
# Creating a tag that will make underlined text
$text->tagConfigure("underline", -underline => 1);
# Creating a tag that changes the color and spacing
$text->tagConfigure("bigblue", -foreground => "blue", -spacing2 => 6);

You can change the settings for an already created tag by using tagConfigure a second time. Any changes you make to the tag immediately affect any text on the screen that has that tag:

# Add background color to "blue" tag
$text->tagConfigure("blue", -background => "red");
# Change the spacing for "bigblue"
$text->tagConfigure("bigblue", -spacing2 => 12);

As with widget configure methods, you can use tagConfigure to find the current settings for a specific tag. To get all the tag options and their values in a list of lists:

@listoflists = $text->tagConfigure("blue");
foreach $l (@list) { print "@$l\n"; }  # print it out

Each list within the list contains two elements: the option name and the value. You can limit the information you retrieve to a single option:

($option, $value) = $text->tagConfigure("blue", -font);

If you only want information on the value for a particular option, use tagCget:

$value = $text->tagCget("bigblue", -spacing2)

8.5.6. Using bind with Tags

One of the main reasons for tags is the ability to assign a binding to certain portions of the text. After creating a tag with tagConfigure, you can use bind so a callback will execute when a sequence of events happens (such as a mouseclick) on that tagged text. On our Button widgets, we have a default binding of <Button-1> that invokes the callback associated with the -command option. We can do the same thing with tagged text.

The best example is using text like a web hyperlink. When you click on the link, something happens: a new document is loaded, or another window is created and presented to the user. The basic form of a tagBind call is as follows:

$text->tagBind(tagname [, sequence, callback ] )

The callback is similar to that specified for the -command callback on a Button. The sequence is a description of the event that triggers the script. The only sequences you can specify are those that are keyboard or mouse related. (See Chapter 15, "Anatomy of the MainLoop" for more details on available events.)

The following code shows a psuedo-link example. All the link does when we click on it is show the end of the Text widget:

$t = $mw->Scrolled("Text", -width => 40)->pack(-expand => 1, 
                                               -fill => 'both');
$t->tagConfigure('goto_end', -underline => 1, -foreground => 'red');
$t->tagBind('goto_end', "<Button-1>", sub { shift->see('end'); } );

# Setup Bindings to change cursor when over that line
$t->tagBind('goto_end', "<Any-Enter>", 
             sub { shift->configure(-cursor => 'hand2') });
$t->tagBind('goto_end', "<Any-Leave>", 
             sub { shift->configure(-cursor => 'xterm') });
$t->insert('end', "END\n", "goto_end");

# Insert a bunch of lines
for ($i = 1; $i <= 100; $i++) {
  $t->insert('end', "$i\n");

Inside the subs in the tagBind calls, we use the shift command to invoke a method. We can do this because the first argument sent to the bind callback is the Text widget. This is done implicitly for you. Whichever widget tagBind is invoked on is the widget that will be sent as the first argument to the callback. To use the Text widget more than once in the callback, assign it to a lexical variable; for example, my $widget = shift.

If we created our Text widget in the global scope of the program and placed a reference to the widget in the variable $t, we could also access the Text widget in the callback via the $t variable. This is only possible because $t is in the global scope and available during the callback. If you have two different Text widgets with which you want to use the same callback, use shift to get the correct Text widget:

$t1->tagBind('goto_end', "<Button-1>", \&goto_end );
$t2->tagBind('goto_end', "<Button-1>", \&goto_end );
sub goto_end {
  my $text = shift;

Using the same callback for both Text widgets helps save space in your program.

To determine the bindings for a tagname, use tagBind with the tag name argument only:

@bindings = $text->tagBind("tagname");

The list will be empty if there are no bindings currently for that tag.

8.5.7. Deleting All Instances of a Tag

Once a tag is created, you can use the tagDelete method to delete the tag:

$text->tagDelete(tagname [ , tagname ... ])

The tags are deleted completely when you use tagDelete. This means the text reverts back to the default configuration values, and any bindings or other information associated with those tags is also deleted.

The tagDelete method can be used if you are creating temporary tags dynamically within the program and need to delete the tags later when the information is no longer valid.

Library Navigation Links

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