Tk Tutorial - 13. Text

Text widgets are created using the Text function:

text = Text(parent, width=40, height=10)

The Basics

If you just want to use the text widget to get a simple multi-line text from the user as part of a form, there's only a few things you'll need to worry about: creating and sizing the widget (check),providing an initial value for the text in the form, and retrieving the text in the widget after the user has submitted the form.

Providing Initial Content

Unlike for example the entry widget, text widgets don't support a "textvariable" configuration option.

Instead, to set the initial text for the widget, you'll use the widget's "insert" method:

text.insert('1.0', 'here is my text to insert')
The "1.0" here represents where to insert the text, and can be read as "line 1, character 0". Line numbers are 1-based, and character numbers are 0-based.

To do, simply embed "\n" (newline) characters in your string at the appropriate locations.

Scrolling

Scrollbars, both horizontal and vertical, can be attached to the text widget.

You can also ask the widget to ensure that a certain part of the text is visible. For example, you want to ensure that the top of the text rather than the bottom is visible, call the "see" method,passing it the position of the text (e.g. "1.0").

Controlling Wrapping

Disabling the Widget

To prevent the user from making any changes to a text widget, set the "state" configuration option to "disabled"; re-enable editing by setting this option back to "normal".

Retrieving the Text

Finally, after the user has made any changes and submitted the form, your program will want to retrieve the contents of the widget, which is done with the "get" method:

thetext = text.get('1.0', 'end')

Modifying the Text in Code

Adding text is done with the "insert" method, which we used above to provide an initial value for the text widget.

Text Positions and Indices

Note that Tk will always add a newline at the very end of the text widget.

Here are a few additional examples of indices, and what they mean:

3.end The newline at the end of line 3.
1.0 + 3 chars Three characters past the start of line 1.
2.end -1 chars The last character before the new line in line 2.
end -1 chars The newline that Tk always adds at the end of the text.
end -2 chars The actual last character of the text.
end -1 lines The start of the last actual line of text.
2.2 + 2 lines The third character (index 2) of the fourth line of text.
2.5 linestart The first character of line 2.
2.5 lineend The position of the newline at the end of line 2.
2.5 wordstart The first character of the word containing the character at index 2.5.
2.5 wordend The first character just past the last character of the word containing index 2.5.
Some additional things to keep in mind:

  • The term "chars" can be abbreviated as "c", and "lines" as "l".
  • You can omit the spaces between the terms, e.g. "1.0+3c".
  • If you specify an index past the end of the widget (e.g. "end + 100c") it will be interpreted as the end.
  • Adding characters will wrap to the next lines as needed; e.g. "1.0 + 10 chars" on a line with only five characters will end up being on the second line.
  • When using indices containing multiple words, make sure to quote them appropriately so that Tk sees the entire index as a single argument.
  • When moving up or down a certain number of lines, this is interpreted as logical lines, where each line is terminated only by the "\n". With long lines and wrapping enabled, this may be represent multiple lines on the display. If you'd like to move up or down a single line on the display, you can specify this as e.g. "1.0 + 2 display lines".
  • To determine the actual canonical position of an index, use the "index" method, passing it the index expression, and it will return the corresponding index in the form "line.char".
  • You can compare two indices using the "compare" method, which lets you check for equality, whether one index is later in the text than the other, etc.

Deleting Text

While the "insert" method adds new text anywhere in the widget, the "delete" method removes it.

text.delete('1.0', '2.0')

There is also a "replace" method, taking a starting index, and ending index and a string as parameters.It does the same as a delete, followed by an insert at the same location.

Example: Logging Window

Here's a short example illustrating how to use a text widget as a 80x24 logging window for your application.

from tkinter import *
from tkinter import ttk

root = Tk()
log = Text(root, state='disabled', width=80, height=24, wrap='none')
log.grid()

def writeToLog(msg):
    numlines = log.index('end - 1 line').split('.')[0]
    log['state'] = 'normal'
    if numlines==24:
        log.delete(1.0, 2.0)
    if log.index('end-1c')!='1.0':
        log.insert('end', '\n')
    log.insert('end', msg)
    log['state'] = 'disabled

Formatting with Tags

Tk's text widget implements these using a feature called tags.

Tags are objects associated with the text widget. Each tag is referred to via a name chosen by the programmer. Though tags are objects having state, they don't need to be explicitly created;they'll be automatically created the first time the tag name is used.

Adding Tags to Text

Tags can be added to ranges of text using the "tag add" method, e.g.

text.tag_add('highlightline', '5.0', '6.0')
Tags can also be provided when inserting text by adding an optional parameter to the "insert" method,which holds a list of one or more tags to add to the text you're inserting, e.g.

text.insert('end', 'new material to insert', ('highlightline', 'recent', 'warning'))

Applying Formatting to Tags

Formatting is applied to tags via configuration options; these work similarly to configuration options for the entire widget. As an example:

text.tag_configure('highlightline', background='yellow', font='helvetica 14 bold', relief='raised')
The currently available configuration options for tags are: "background", "bgstipple", "borderwidth", "elide", "fgstipple", "font", "foreground", "justify", "lmargin1", "lmargin2", "offset", "overstrike", "relief", "rmargin", "spacing1", "spacing2", "spacing3", "tabs", "tabstyle", "underline", and "wrap". Check the reference manual for detailed descriptions of these. The "tag cget" method allows you to query the configuration options of a tag.

Because multiple tags can apply to the same range of text, there is the possibility for conflict (e.g. two tags specifying different fonts). A priority order is used to resolve these; the most recently created tags have the highest priority, but priorities can be rearranged using the "tag raise" and "tag lower" methods.

More Tag Manipulations

To delete a tag altogether, you can use the "tag delete" method. You can also remove a tag from a range of text using the "tag remove" method; even if that leaves no ranges of text with that tag, the tag object itself still exists.

The "tag ranges" method will return a list of ranges in the text that the tag has been applied to. There are also "tag nextrange" and "tag prevrange" methods to search forward or backward for the first such range from a given position.

The "tag names" method, called with no additional parameters, will return a list of all tags currently defined in the text widget (including those that may not be presently used).

Finally, you can use the first and last characters in the text having a given tag as indices, the same way you can use "end" or "2.5". To do so, just specify "tagname.first" or "tagname.last".

Differences between Tags in Canvas and Text Widgets

While both canvas and text widgets support "tags" which can be used to apply to several objects, style them, and so on,these tags are not the same thing. There are important differences to take note of.

In canvas widgets, individual canvas items have configuration options that control their appearance. When you refer to a tag in a canvas, the meaning of that is identical to "all canvas items presently having that tag". The tag itself doesn't exist as a separate object. So in the following snippet, the last rectangle added will not be colored red.

canvas.itemconfigure('important', fill='red')
canvas.create_rectangle(10, 10, 40, 40, tags=('important'))
In text widgets by contrast, it's not the individual characters that retain the state information about appearance,but tags, which are objects in their own right. So in this snippet, the newly added text will be colored red.

text.insert('end', 'first text', ('important'))
text.tag_configure('important', foreground='red')
text.insert('end', 'second text', ('important'))

Events and Bindings

One quite cool thing is that you can define event bindings on tags. That allows you to do things like easily recognize mouse clicks just on particular ranges of text, and popup up a menu or dialog in response. Different tags can have different bindings. Bindings on tags are implemented using the "tag bind" method:

text.tag_bind('important', '<1>', popupImportantMenu)
Besides the normal low-level events,there are also two virtual events that will be generated: <Modified> whenever a change is made to the content of the widget, and <Selection> whenever there is a change made to which text is selected.

Selecting Text

Your program may want to know if a range of text has been selected by the user, and if so, what that range is. While you can tell when the selection has changed (e.g. to update whether or not the bold button is active) via the <Selection>virtual event, that doesn't tell you what has been selected.

The text widget automatically maintains a tag named "sel", which refers to the selected text. Whenever the selection changes, the "sel" tag will be updated. So you can find the range of text selected using the"tag ranges" method, passing it "sel" as the tag to report on.

Similarly, you can change the selection by using "tag add" to set a new selection, or "tag remove"to remove the selection. You can't actually delete the "sel" tag of course.

The text widget manages the concept of the insertion cursor (where newly typed text will appear) separate from the selection. It does so using a new concept called a mark.

Marks

Marks are used to indicate a particular place in the text.

Tk automatically maintains two different marks. The first is named "insert", and is the present location of the insertion cursor. As the cursor is moved (via mouse or keyboard), the mark moves with it. The second mark is named "current", and reflects the position of the character underneath the current mouse position.

To create your own marks, use the widget's "mark set" method, passing it the name of the mark, and an index(the mark is positioned just before the character at the given index). This is also used to move an existing mark toa different position. Marks can be removed using the "mark unset" method, passing it the name of the mark.If you delete a range of text containing a mark, that also removes the mark.

The name of a mark can also be used as an index (in the same way "1.0" or "end-1c" are indices). You can find the next mark (or previous one) from a given index in the text using the "mark next" or "mark previous" methods. The "mark names" method will return a list of the names of all marks.

Marks also have a gravity, which can be modified with the "mark gravity" method, which affects what happens when text is inserted at the mark. Suppose we have the text "ac", with a mark in between that we'll symbolize with a pipe, i.e. "a|c". If the gravity of that mark is "right" (the default) the mark will attach itself to the "c". If the new text "b" is inserted at the mark, the mark will remain stuck to the "c",and so the new text will be inserted before the mark, i.e. "ab|c". If the gravity is instead "left", the mark will attach itself to the "a", and so new text will be inserted after the mark, i.e. "a|bc".

Images and Widgets

Like canvas widgets, text widgets can contain not only text, but also images and any other Tk widgets (including a frame itself containing many other widgets).

flowers = PhotoImage(file='flowers.gif')
text.image_create('sel.first', image=flowers)
Widgets are added to a text widget pretty much the same way as images. The widget you're adding should be a descendant of the text widget in the overall window hierarchy.

b = ttk.Button(text, text='Push Me')
text.window_create('1.0', window=b)

Even More

Search

The text widget includes a powerful "search" method which allows you to locate a piece of text within the widget; this is useful for a "Find" dialog, as one obvious example.

Modifications, Undo and Redo

The text widget keeps track of whether or not changes have been made to the text (useful to know whether you need to save it for example), which you can query (or change) using the "edit modified" method. There is also a complete multi-level undo/redo mechanism, managed automatically by the widget when you set its "undo" configuration option to true. Calling "edit undo" or "edit redo" then will modify the current text using information stored on the undo/redo stack.

Eliding Text

You can actually include text in the widget that is not displayed; this is known as "elided" text, and is made available using the "elide" configuration option for tags.

Introspection

Like most Tk widgets, the text widget goes out of its way to expose information about its internal state; we've seen most of this in terms of the "get" method, widget configuration options, "names" and"cget" for both tags and marks, and so on. There is even more information available that you can use for a wide variety of tasks. Check out the "debug", "dlineinfo", "bbox", "count" and "dump" methods in the reference manual.

Peering

The Tk text widget allows the same underlying text data (containing all the text, marks, tags, images, and so on) to be shared between two or more different text widgets. This is known as peering, and is controlled via the"peer" method.

from: http://www.tkdocs.com/tutorial/text.html

發佈了119 篇原創文章 · 獲贊 16 · 訪問量 24萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章