For added precision, you can add simple arithmetic extensions to index strings. The
index expression END+'-1c' in the get call in the previous example, for instance, is really
the string 'end-1c' and refers to one character back from END. Because END points to
just beyond the last character in the text string, this expression refers to the last char-
acter itself. The −1c extension effectively strips the trailing \n that this widget adds to
its contents (and which may add a blank line if saved in a file).
Similar index string extensions let you name characters ahead (+1c), name lines ahead
and behind (+2l, −2l), and specify things such as line ends and word starts around an
index (lineend, wordstart). Indexes show up in most Text widget calls.
Besides row/column identifier strings, you can also pass positions as names
of marks—symbolic names for a position between two characters. Unlike absolute row/
column positions, marks are virtual locations that move as new text is inserted or de-
leted (by your script or your user). A mark always refers to its original location, even if
that location shifts to a different row and column over time.
To create a mark, call the Text object’s mark_set method with a string name and an
index to give its logical location. For instance, this script sets the insert cursor at the
start of the text initially, with a call like the first one here:
self.text.mark_set(INSERT, '1.0') # set insert cursor to start
self.text.mark_set('linetwo', '2.0') # mark current line 2
The name INSERT is a predefined special mark that identifies the insert cursor position;
setting it changes the insert cursor’s location. To make a mark of your own, simply
provide a unique name as in the second call here and use it anywhere you need to specify
a text position. The mark_unset call deletes marks by name.
In addition to absolute indexes and symbolic mark names, the Text widget
supports the notion of tags—symbolic names associated with one or more substrings
within the Text widget’s string. Tags can be used for many things, but they also serve
to represent a position anywhere you need one: tagged items are named by their be-
ginning and ending indexes, which can be later passed to position-based calls.
For example, tkinter provides a built-in tag name, SEL—a tkinter name preassigned to
string 'sel'—which automatically refers to currently selected text. To fetch the text
selected (highlighted) with a mouse, run either of these calls:
text = self.text.get(SEL_FIRST, SEL_LAST) # use tags for from/to indexes
text = self.text.get('sel.first', 'sel.last') # strings and constants work
The names SEL_FIRST and SEL_LAST are just preassigned variables in the tkinter module
that refer to the strings used in the second line here. The text get method expects two
indexes; to fetch text names by a tag, add .first and .last to the tag’s name to get its
start and end indexes.
To tag a substring, call the Text widget’s tag_add method with a tag name string and
start and stop positions (text can also be tagged as added in insert calls). To remove
a tag from all characters in a range of text, call tag_remove:
Text marks.
Text tags.
532 | Chapter 9: A tkinter Tour, Part 2