An Introduction to Tkinter
前页 | Chapter 42. The Text Widget | 后页

# Concepts

The text widget stores and displays lines of text.

The text body can consist of characters, marks, and embedded windows or images. Different regions can be displayed in different styles, and you can also attach event bindings to regions.

By default, you can edit the text widget's contents using the standard keyboard and mouse bindings. To disable editing, set the `state` option to `DISABLED` (but if you do that, you'll also disable the `insert` and `delete` methods).

## Indexes

Indexes are used to point to positions within the text handled by the text widget. Like Python sequence indexes, text widget indexes correspond to positions between the actual characters.

Tkinter provides a number of different index types:

- line/column ("line.column")

- line end ("line.end")

- `INSERT`

- `CURRENT`

- `END`

- user-defined marks

- user-defined tags ("tag.first", "tag.last")

- selection (`SEL_FIRST`, `SEL_LAST`)

- window coordinate ("@x,y")

- embedded object name (window, images)

- expressions

### Lines and columns

line/column indexes are the basic index type. They are given as strings consisting of a line number and column number, separated by a period. Line numbers start at 1, while column numbers start at 0, like Python sequence indexes. You can construct indexes using the following syntax:

        "%d.%d" % (line, column)

It is not an error to specify line numbers beyond the last line, or column numbers beyond the last column on a line. Such numbers correspond to the line beyond the last, or the newline character ending a line.

Note that line/column indexes may look like floating point values, but it's seldom possible to treat them as such (consider position 1.25 vs. 1.3, for example). I sometimes use `1.0` instead of "1.0" to save a few keystrokes when referring to the first character in the buffer, but that's about it.

You can use the `index` method to convert all other kinds of indexes to the corresponding line/column index string.

### Line endings

A line end index is given as a string consisting of a line number directly followed by the text "`.end`". A line end index correspond to the newline character ending a line.

### Named indexes

`INSERT` (or "insert") corresponds to the insertion cursor.

`CURRENT` (or "current") corresponds to the character closest to the mouse pointer. However, it is only updated if you move the mouse without holding down any buttons (if you do, it will not be updated until you release the button).

`END` (or "end") corresponds to the position just after the last character in the buffer.

User-defined marks are named positions in the text. `INSERT` and `CURRENT` are predefined marks, but you can also create your own marks. See below for more information.

User-defined tags represent special event bindings and styles that can be assigned to ranges of text. For more information on tags, see below.

You can refer to the beginning of a tag range using the syntax "tag`.first`" (just before the first character in the text using that tag), and "tag`.last`" (just after the last character using that tag).

        "%s.first" % tagname
        "%s.last" % tagname

If the tag isn't in use, Tkinter raises a `TclError` exception.

The selection is a special tag named `SEL` (or "sel") that corresponds to the current selection. You can use the constants `SEL_FIRST` and `SEL_LAST` to refer to the selection. If there's no selection, Tkinter raises a `TclError` exception.

### Coordinates

You can also use window coordinates as indexes. For example, in an event binding, you can find the character closest to the mouse pointer using the following syntax:

        "@%d,%d" % (event.x, event.y)

### Embedded objects

Embedded object name can be used to refer to windows and images embedded in the text widget. To refer to a window, simply use the corresponding Tkinter widget instance as an index. To refer to an embedded image, use the corresponding Tkinter `PhotoImage` or `BitmapImage` object.

### Expressions

Expressions can be used to modify any kind of index. Expressions are formed by taking the string representation of an index (use `str` if the index isn't already a string), and appending one or more modifiers from the following list:

- "`+` count `chars`" moves the index forward. The index will move over newlines, but not beyond the `END` index.

- "`-` count `chars`" moves the index backwards. The index will move over newlines, but not beyond index "1.0".

- "`+` count `lines`" and "`-` count `lines`" moves the index full lines forward (or backwards). If possible, the index is kept in the same column, but if the new line is too short, the index is moved to the end of that line.

- "`linestart`" moves the index to the first position on the line.

- "`lineend`" the index to the last position on the line (the newline, that is).

- "`wordstart`" and "`wordend`" moves the index to the beginning (end) of the current word. Words are sequences of letters, digits, and underline, or single non-space characters.

The keywords can be abbreviated and spaces can be omitted as long as the result is not ambigous. For example, "`+ 5 chars`" can be shortened to "`+5c`".

For compatibility with implementations where the constants are not ordinary strings, you may wish to use `str` or formatting operations to create the expression string. For example, here's how to remove the character just before the insertion cursor:

        def backspace(event):
            event.widget.delete("%s-1c" % INSERT, INSERT)

## Marks

Marks are (usually) invisible objects embedded in the text managed by the widget. Marks are positioned between character cells, and moves along with the text.

- user-defined marks

- `INSERT`

- `CURRENT`

You can use any number of user-defined marks in a text widget. Mark names are ordinary strings, and they can contain anything except whitespace (for convenience, you should avoid names that can be confused with indexes, especially names containing periods). To create or move a mark, use the `mark_set` method.

Two marks are predefined by Tkinter, and have special meaning:

`INSERT` (or "insert") is a special mark that is used to represent the insertion cursor. Tkinter draws the cursor at this mark's position, so it isn't entirely invisible.

`CURRENT` (or "current") is a special mark that represents the character closest to the mouse pointer. However, it is only updated if you move the mouse without holding down any buttons (if you do, it will not be updated until you release the button).

Special marks can be manipulated as other user-defined marks, but they cannot be deleted.

If you insert or delete text before a mark, the mark is moved along with the other text. To remove a mark, you must use the `mark_unset` method. Deleting text around a mark doesn't remove the mark itself.

If you insert text at a mark, it may be moved to the end of that text or left where it was, depending on the mark's gravity setting (`LEFT` or `RIGHT`; default is `RIGHT`). You can use the `mark_gravity` method to change the gravity setting for a given mark.

In the following example, the "sentinel" mark is used to keep track of the original position for the insertion cursor.

        text.mark_set("sentinel", INSERT)
        text.mark_gravity("sentinel", LEFT)

You can now let the user enter text at the insertion cursor, and use `text.get("sentinel", INSERT)` to pick up the result.

## Tags

Tags are used to associated a display style and/or event callbacks with ranges of text.

- user-defined tags

- `SEL`

You can define any number of user-defined tags. Any text range can have multiple tags, and the same tag can be used for many different ranges. Unlike the `Canvas` widget, tags defined for the text widget are not tightly bound to text ranges; the information associated with a tag is kept also if there is no text in the widget using it.

Tag names are ordinary strings, and they can contain anything except whitespace.

`SEL` (or "sel") is a special tag which corresponds to the current selection, if any. There should be at most one range using the selection tag.

The following options are used with `tag_config` to specify the visual style for text using a certain tag.

Table 42-1. Text Tag Options

Option | Type | Description
--- | --- | ---
`background` | color | The background color to use for text having this tag. Note that the `bg` alias cannot be used with tags; it is interpreted as `bgstipple` rather than `background`.
`bgstipple` (or `bg`) | bitmap | The name of a bitmap which is used as a stipple brush when drawing the background. Typical values are "gray12", "gray25", "gray50", or "gray75". Default is a solid brush (no bitmap).
`borderwidth` | distance | The width of the text border. The default is 0 (no border). Note that the `bd` alias cannot be used with tags.
`fgstipple` (or `fg`) | bitmap | The name of a bitmap which is used as a stipple brush when drawing the text. Typical values are "gray12", "gray25", "gray50", or "gray75". Default is a solid brush (no bitmap).
`font` | font | The font to use for text having this tag.
`foreground` | color | The color to use for text having this tag. Note that the `fg` alias cannot be used with tags; it is interpreted as `fgstipple` rather than `foreground`.
`justify` | constant | Controls text justification (the first character on a line determines how to justify the whole line). Use one of `LEFT`, `RIGHT`, or `CENTER`. Default is `LEFT`.
`lmargin1` | distance | The left margin to use for the first line in a block of text having this tag. Default is 0 (no left margin).
`lmargin2` | distance | The left margin to use for every line but the first in a block of text having this tag. Default is 0 (no left margin).
`offset` | distance | Controls if the text should be offset from the baseline. Use a positive value for superscripts, a negative value for subscripts. Default is 0 (no offset).
`overstrike` | flag | If non-zero, the text widget draws a line over the text that has this tag. For best results, you should use overstrike fonts instead.
`relief` | constant | The border style to use for text having this tag. Use one of `SUNKEN`, `RAISED`, `GROOVE`, `RIDGE`, or `FLAT`. Default is `FLAT` (no border).
`rmargin` | distance | The right margin to use for blocks of text having this tag. Default is 0 (no right margin).
`spacing1` | distance | Spacing to use above the first line in a block of text having this tag. Default is 0 (no extra spacing).
`spacing2` | distance | Spacing to use between the lines in a block of text having this tag. Default is 0 (no extra spacing).
`spacing3` | distance | Spacing to use after the last line of text in a block of text having this tag. Default is 0 (no extra spacing).
`tabs` | string |
`underline` | flag | If non-zero, the text widget underlines the text that has this tag. For example, you can get the standard hyperlink look with (foreground="blue", underline=1). For best results, you should use underlined fonts instead.
`wrap` | constant | The word wrap mode to use for text having this tag. Use one of `NONE`, `CHAR`, or `WORD`.

If you attach multiple tags to a range of text, style options from the most recently created tag override options from earlier tags. In the following example, the resulting text is blue on a yellow background.

        text.tag_config("n", background="yellow", foreground="red")
        text.tag_config("a", foreground="blue")
        text.insert(contents, ("n", "a"))

Note that it doesn't matter in which order you attach tags to a range; it's the tag creation order that counts.

You can change the tag priority using the `tag_raise` and `tag_lower`. If you add a `text.tag_lower("a")` to the above example, the text becomes red.

The `tag_bind` method allows you to add event bindings to text having a particular tag. Tags can generate mouse and keyboard events, plus `<Enter>` and `<Leave>` events. For example, the following code snippet creates a tag to use for any hypertext links in the text:

        text.tag_config("a", foreground="blue", underline=1)
        text.tag_bind("a", "<Enter>", show_hand_cursor)
        text.tag_bind("a", "<Leave>", show_arrow_cursor)
        text.tag_bind("a", "<Button-1>", click)
        text.config(cursor="arrow")

        text.insert(INSERT, "click here!", "a")

前页 | Home | 后页
The Text Widget | Up | Patterns