17.6. The Text Widget
Class Text implements a powerful multiline text editor, which can display images and embedded widgets as well as text in one or more fonts and colors. An instance t of Text supports many ways to refer to specific points in t's contents. t supplies methods and configuration options, which allows fine-grained control of operations, content, and rendering. This section covers a large, frequently used subset of this vast functionality. In some very simple cases, you can get by with just three Text-specific idioms:
t.delete('1.0', END) # clear the widget's contents t.insert(END, astring) # append astring to the widget's contents somestring = t.get('1.0', END) # get the widget's contents as a string
END is an index on any Text instance t, indicating the end of t's text. '1.0' is also an index, indicating the start of t's text (first line, first column). For more about indices, see "Indices" on page 432.
17.6.1. The ScrolledText Module
The ScrolledText module of Python's standard library supplies a class named ScrolledText. To construct a ScrolledText instance, call ScrolledText.ScrolledText in exactly the same way you would call Tkinter.Text. A ScrolledText instance s is exactly the same as a Text instance, except that s automatically provides a scrollbar for the Text instance it wraps.
17.6.2. Text Widget Methods
An instance t of Text supplies many methods. (Methods dealing with marks and tags are covered in "Marks" on page 428 and "Tags" on page 429.) Many methods accept one or two indices into t's contents. The most frequently used methods are the following.
A mark on a Text instance t is a name that indicates a point within the contents of t. INSERT and CURRENT are predefined marks on any Text instance t, with predefined meanings. INSERT names the point where the insertion cursor (also known as the text caret) is located in t. By default, when the user enters text at the keyboard with the focus on t, t inserts the text at index INSERT. CURRENT names the point in t that was closest to the mouse cursor when the user last moved the mouse within t. By default, when the user clicks the mouse on t, t gets focus and sets INSERT to CURRENT.
To set other marks on t, call method t.mark_set. Each mark is an arbitrary string without whitespace. To avoid confusion with other forms of index, use no punctuation in a mark. A mark is an index, as covered in "Indices" on page 432; you can pass a string that is a mark on t wherever a method of t accepts an index argument.
When you insert or delete text before a mark m, m moves accordingly. Deleting a portion of text that surrounds m does not remove m. To remove a mark on t, call method t.mark_unset. What happens when you insert text at a mark m depends on m's gravity setting, which can be RIGHT (the default) or LEFT. When m has gravity RIGHT, m moves to remain at the end (i.e., to the right) of text inserted at m. When m has gravity LEFT, m does not move when you insert text at m: text inserted at m goes after m, and m itself remains at the start (i.e., to the left) of such inserted text.
A Text instance t supplies the following methods related to marks on t.
A tag on a Text instance t is a symbolic name that indicates zero or more regions (ranges) in the contents of a Text instance t. SEL is a predefined tag on any Text instance t and names a single range of t that is selected, normally by the user dragging over it with the mouse. Tkinter typically displays the SEL range with distinctive background and foreground colors. To create other tags on t, call the t.tag_add or t.tag_config method, or use optional parameter tags of method t.insert. The ranges of various tags on t may overlap. t renders text that has several tags by using options from the uppermost tag, according to calls to methods t.tag_raise or t.tag_lower. By default, a tag created more recently is above one created earlier.
Each tag is an arbitrary string that contains no whitespace. Each tag has two indices: first (start of the tag's first range) and last (end of the tag's last range). You can pass a tag's index wherever a method of t accepts an index argument. SEL_FIRST and SEL_LAST indicate the first and last indices of predefined tag SEL.
A Text instance t supplies the following methods related to tags on t.
All ways to indicate a spot in the contents of a Text instance t are known as indices on t. The basic form of an index is a string of the form '%d.%d'%(L,C), which indicates the spot in the text that is at line L (the first line is 1), column C (the first column is 0). For example, '1.0' is a basic-form index that indicates the start of text for any t. t.index(i) returns the basic-form equivalent to an index i of any form.
END is an index that indicates the end of text for any t. '%d.end'%L, for any line number L, is an index that indicates the end (the '\n' end-of-line marker) of line L. For example, '1.end' indicates the end of the first line. To get the number of characters in line number L of a Text instance t, you can use:
def line_length(t, L): return int(t.index('%d.end'%L).split('.')[-1])
'@%d,%d'%(x,y) is also an index on t, where x and y are coordinates in pixels within t's window.
Any tag on t is associated with two indices: strings '%s.first'%tag (start of tag's first range) and '%s.last'%tag (end of tag's last range). For example, right after t.tag_add('mytag',i,j), 'mytag.first' indicates the same spot in t as index i, and 'mytag.last' indicates the same spot in t as index j. Using index 'x.first' or 'x.last' when t has no tag 'x' raises an exception.
SEL_FIRST and SEL_LAST are indices (start and end of the selection, SEL tag). Using SEL_FIRST or SEL_LAST when there is no selected range on t raises an exception.
Marks (covered in "Marks" on page 428), including predefined marks INSERT and CURRENT, are also indices. Any image or widget embedded in t is also an index on t (methods image_create and window_create are covered in image_create on page 427 and window_create on page 428).
Another form of index, index expressions, concatenates to the string form of any index one or more of the following modifier string literals:
You can optionally omit spaces and abbreviate keywords down to one character. For example, '%s-4c'%END means "four characters before the end of t's text contents," and '%s+1line linestart'%SEL_LAST means "the start of the line immediately after the line where t's selection ends."
A Text instance t supplies two methods related to indices on t.
You can change the font on any Tkinter widget with option font=font. In most cases, it makes no sense to change widgets' fonts. However, in Text instances, and for specific tags on them, changing fonts can be quite useful.
Module tkFont supplies class Font; attributes BOLD, ITALIC, and NORMAL to define font characteristics; and functions families (returns a sequence of strings that name all families of available fonts) and names (returns a sequence of strings that name all user-defined fonts). Frequently used font options are:
An instance F of Font supplies the following frequently used methods.
17.6.7. Text Example
To exemplify some of the many features of class Text, the following example shows one way to highlight all occurrences of a string in the text:
from Tkinter import * root = Tk( ) # at top of root, left to right, put a Label, an Entry, and a Button fram = Frame(root) Label(fram,text='Text to find:').pack(side=LEFT) edit = Entry(fram) edit.pack(side=LEFT, fill=BOTH, expand=1) edit.focus_set( ) butt = Button(fram, text='Find') butt.pack(side=RIGHT) fram.pack(side=TOP) # fill rest of root with a Text and put some text there text = Text(root) text.insert('1.0', '''Nel mezzo del cammin di nostra vita mi ritrovai per una selva oscura che la diritta via era smarrita ''') text.pack(side=BOTTOM) # action-function for the Button: highlight all occurrences of string def find( ): # remove previous uses of tag 'found', if any text.tag_remove('found', '1.0', END) # get string to look for (if empty, no searching) s = edit.get( ) if s: # start from the beginning (and when we come to the end, stop) idx = '1.0' while 1: # find next occurrence, exit loop if no more idx = text.search(s, idx, nocase=1, stopindex=END) if not idx: break # index right after the end of the occurrence lastidx = '%s+%dc' % (idx, len(s)) # tag the whole occurrence (start included, stop excluded) text.tag_add('found', idx, lastidx) # prepare to search for next occurrence idx = lastidx # use a red foreground for all the tagged occurrences text.tag_config('found', foreground='red') # give focus back to the Entry field edit.focus_set( ) # install action-function to execute when user clicks Button butt.config(command=find) # start the whole show (go event-driven) root.mainloop( )
This example also shows how to use a Frame to perform a simple widget layout task (put three widgets side by side with the Text below them all). Figure 17-1 shows this example in action.
Figure 17-1. Highlighting in a Text instance