Previous section   Next section

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

Table of Contents
Chapter 33.  The Text Widget

Text Tags

A tag is a symbolic name that is associated with one or more ranges of characters. A tag has attributes that affect the display of text that is tagged with it. These attributes include fonts, colors, tab stops, line spacing and justification. A tag can have event bindings so you can create hypertext. A tag can also be used to represent application-specific information. The tag names and tag ranges operations described later tell you what tags are defined and where they are applied.

You can use almost any string for the name of a tag. However, do not use pure numbers, and do not include spaces, plus (+) or minus (-). These characters are used in the mark arithmetic and may cause problems if you use them in tag names.

A tag is added to a range with the tag add operation. The following command applies the tag everywhere to all the text in the widget:

$t tag add everywhere 1.0 end

You can add one or more tags when text is inserted, too:

$t insert insert "new text" {someTag someOtherTag}

If you do not specify tags when text is inserted, then the text picks up any tags that are present on the characters on both sides of the insertion point. (Before Tk 4.0, tags from the left-hand character were picked up.) If you specify tags in the insert operation, only those tags are applied to the text.

A tag is removed from a range of text with the tag remove operation. However, even if there is no text labeled with a tag, its attribute settings are remembered. All information about a tag can be removed with the tag delete operation:

$t tag remove everywhere 3.0 6.end
$t tag delete everywhere

Tag Attributes

The attributes for a tag are defined with the tag configure operation. For example, a tag for blue text is defined with the following command:

$t tag configure blue -foreground blue

Table 33-3 specifies the set of attributes for tags. Some attributes can only be applied with tags; there is no global attribute for -bgstipple, -fgstipple, -justify, -lmargin1, -lmargin2, -offset, -overstrike, -rmargin, and -underline. Table 33-10 on page 474 lists the attributes for the text widget as a whole.

The -relief and -borderwidth attributes go together. If you only specify a relief, there is no visible effect. The default relief is flat, too, so if you specify a border width without a relief you won't see any effect either.

The stipple attributes require a bitmap argument. Bitmaps and colors are explained in more detail in Chapter 38. For example, to "grey out" text you could use a foreground stipple of gray50:

$t tag configure disabled -fgstipple gray50

Table 33-3. Attributes for text tags.
-background colorThe background color for text.
-bgstipple bitmapA stipple pattern for the background color.
-borderwidth pixelsThe width for 3D border effects.
-fgstipple bitmapA stipple pattern for the foreground color.
-font fontThe font for the text.
-foreground colorThe foreground color for text.
-justify howJustification: left, right, or center.
-lmargin1 pixelsNormal left indent for a line.
-lmargin2 pixelsIndent for the part of a line that gets wrapped.
-offset pixelsBaseline offset. Positive for superscripts.
-overstrike booleanDraw text with a horizontal line through it.
-relief whatflat, sunken, raised, groove, solid or ridge.
-rmargin pixelsRight-hand margin.
-spacing1 pixelsAdditional space above a line.
-spacing2 pixelsAdditional space above wrapped part of line.
-spacing3 pixelsAdditional space below a line.
-tabs tabstopsSpecifies tab stops.
-underline booleanIf true, the text is underlined.
-wrap modeLine wrap: none, char, or word.


Configure tags early.

You can set up the appearance (and bindings) for tags once in your application, even before you have labeled any text with the tags. The attributes are retained until you explicitly delete the tag. If you are going to use the same appearance over and over again, then it is more efficient to do the setup once so that Tk can retain the graphics context.

On the other hand, if you change the configuration of a tag, any text with that tag will be redrawn with the new attributes. Similarly, if you change a binding on a tag, all tagged characters are affected immediately.

Example 33-1 defines a few tags for character styles you might see in an editor. The example is uses the font naming system added in Tk 8.0, which is described on page 550.

Example 33-1 Tag configurations for basic character styles.
proc TextStyles { t } {
   $t tag configure bold -font {times 12 bold}
   $t tag configure italic -font {times 12 italic}
   $t tag configure fixed -font {courier 12}
   $t tag configure underline -underline true
   $t tag configure super -offset 6 -font {helvetica 8}
   $t tag configure sub -offset -6 -font {helvetica 8}

Mixing Attributes from Different Tags

A character can be labeled with more than one tag. For example, one tag could determine the font, another could determine the background color, and so on. If different tags try to supply the same attribute, a priority ordering is taken into account. The latest tag added to a range of text has the highest priority. The ordering of tags can be controlled explicitly with the tag raise and tag lower commands.

You can achieve interesting effects by composing attributes from different tags. In a mail reader, for example, the listing of messages in a mail folder can use one color to indicate messages that are marked for delete, and it can use another color for messages that are marked to be moved into another folder. The tags might be defined like this:

$t tag configure deleted -background grey75
$t tag configure moved -background yellow

These tags conflict, but they are never used on the same message. However, a selection could be indicated with an underline, for example:

$t tag configure select -underline true

You can add and remove the select tag to indicate what messages have been selected, and the underline is independent of the background color determined by the moved or deleted tag. If you look at the exmh implementation, the ftocColor.tcl file defines several text tags that are composed like this.

Line Spacing and Justification

The spacing and justification for text have several attributes. These settings are complicated by wrapped text lines. The text widget distinguishes between the first display line and the remaining display lines for a given text line. For example, if a line in the text widget has 80 characters but the window is only wide enough for 30, then the line may be wrapped onto three display lines. See Table 33-10 on page 474 for a description of the text widget's wrap attribute that controls this behavior.

Spacing is controlled with three attributes, and there are global spacing attributes as well as per-tag spacing attributes. The -spacing1 attribute adds space above the first display line, while -spacing2 adds space above the subsequent display lines that exist because of wrapping. The -spacing3 attribute adds space below the last display line, which could be the same as the first display line if the line is not wrapped.

The margin settings also distinguish between the first and remaining display lines. The -lmargin1 attribute specifies the indent for the first display line, while the -lmargin2 attribute specifies the indent for the rest of the display lines, if any. There is only a single attribute, -rmargin, for the right indent. These margin attributes are only tag attributes. The closest thing for the text widget as a whole is the -padx attribute, but this adds an equal amount of spacing on both sides:

Example 33-2 Line spacing and justification in the text widget.


proc TextExample { f } {
   frame $f
   pack $f -side top -fill both -expand true
   set t [text $f.t -setgrid true -wrap word \
      -width 42 -height 14 \
      -yscrollcommand "$f.sy set"]
   scrollbar $f.sy -orient vert -command "$f.t yview"
   pack $f.sy -side right -fill y
   pack $f.t -side left -fill both -expand true

   $t tag configure para -spacing1 0.25i -spacing2 0.1i \
      -lmargin1 0.5i -lmargin2 0.1i -rmargin 0.5i
   $t tag configure hang -lmargin1 0.1i -lmargin2 0.5i

   $t insert end "Here is a line with no special settings\n"
   $t insert end "Now is the time for all good women and men
to come to the aid of their country. In this great time of
need, no one can avoid their responsibility.\n"
   $t insert end "The quick brown fox jumps over the lazy dog."

   $t tag add para 2.0 2.end
   $t tag add hang 3.0 3.end

The example defines two tags, para and hang, that have different spacing and margins. The -spacing1 setting for para causes the white space before the second line. The -spacing2 setting causes the white space between the wrapped portions of the second paragraph. The hang tag has no spacing attributes, so the last paragraph starts right below the previous paragraph. You can also see the difference between the -lmargin1 and -lmargin2 settings.

The newline characters are inserted explicitly. Each newline character defines a new line for the purposes of indexing, but not necessarily for display, as this example shows. In the third line there is no newline. This means that if more text is inserted at the end mark, it will be on line three.

The values for the spacing and margin parameters are in screen units. Because different fonts are different sizes, you may need to compute the spacings as a function of the character sizes. The bbox operation returns the bounding box (x, y, width, height) for a given character:

$t insert 1.0 "ABCDE"
$t bbox 1.0
=> 4 4 8 12

The Tk 8.0 font metrics command, which is described on page 554, also gives detailed measurements:

font metrics {times 12}
-ascent 9 -descent 3 -linespace 12 -fixed 0

Text justification is limited to three styles: left, right, or center. There is no setting that causes the text to line up on both margins, which would have to be achieved by introducing variable spacing between words.

Tab Stops

Text widgets have adjustable tab stops. The tabs attribute is a list of tab stops, which are specified with a screen unit and optionally a keyword that indicates justification. The tab justification keywords are left, right, center, and numeric, and these can be abbreviated. The default is left. The following resource specification defines tab stops at 2-centimeter intervals with different justification:

*Text.tabs: 2c left 4c right 6c center 8c numeric

The tabs attribute applies to the whole text widget or to a tag. The last tab stop is extrapolated as needed. The following command defines a tag that has left justified tab stops every half inch:

$t tag configure foo -tabs ".5i left"

      Previous section   Next section