Updated 2014-04-10 10:16:26 by RLE

text, a built-in Tk command, creates a text widget.

Tools  edit

ntext
provides a bindtags binding tag named Ntext for text widgets in place of the default Text binding tag
text::sync
provides routines for synchronizing two or mor Tk text widgets
URL behaviour in a text widget
a minimal package to simulate URL behaviour in a text widget
xtt: XML <--> Text Tag translator
converts tags in a text canvas to and from XML, so you can write up an XML file, then load it into a text widget

Widgets Built on text  edit

Ctext
part of tklib, provides line numbering and syntax highlighting for the text widget
LabelText -A Multi Line Entry Widget
uses text to make an improved entry widget
TkTextPlus
line numbering and syntax highlighting
Multi-Line Text Entry Widget - With Entry Widget Like Field To Field Tabbing
Multi-Line Entry Widget in Snit
Supports -textvariable, handles tabbing and automatic scroll bars
Multiline expanding entry widget
similar
stext
features suitable for source code displaying and editing
Read-Only Text Megawidget with TclOO

Examples  edit

SQL
includes a small example by Vincent Thomas
a simple file-viewing text widget
also demonstrates a scrollbar well, in a small example
A simple slideshow
A simple serial terminal
How to build a simple serial terminal in a text widget
A little NNTP reader
A little Unicode editor
A small editor in 8.5.0
Simple search and replace
htext
hypertext system
Text widget example
Tailing widget
very simple example

Technique  edit

A change-sensitive text widget
made easier since Tk 8.4 by the <<Modified>> virtual event TIP 26
a way to 'pipe' from an external process into a text widget
Auto extending text widget tags
autoreplace
turn (TM) to (TM) as you type
jump words like emacs in the text widget
line numbers in text widget
Looping over the contents of a text widget
Maintaining indentation in a text widget when go to a new line
Move cursor by display line in a text widget
Multi-column display in text widget
Read-only text widget
rtext
Searching in a text widget
Serializing a text widget
Show me all!
how to show all the lines
Super and Subscripts in a text widget
Text variable for text widget
Text Widget Newline Wrapping
Text Widget Syntax Highlighting
Text widget undo/redo limitations and enhancements
this facility has been available since 8.4. Text widget undo/redo discusses two scripted solutions for older versions of Tcl/Tk.
Need Help: TCL\TK - adding multiple buttons in frame
AMG answers this need with the text widget
Round Corner Text Widget

Synopsis  edit

text pathName ?options?

tk_textCopy pathName

tk_textCut pathName

tk_textPaste pathName

Documentation  edit

official reference
also documents tk_textCopy, tk_textCut, and tk_textPaste
The Tk Text Widget, Derek Fountain, 2004-01-15
a nice introduction to text

History  edit

New release of Tcl and Tk, 1992-08-07
text widget announced.

Description  edit

text, along with canvas are the two "Swiss Army" widgets for creating powerful semi-custom components. A text widget can be anything from a multi-line entry to a fully functional Web browser.

For a list of all pages that refer to the text widget, click on the title of this page.

Widget Bindings  edit

One of the really nice features of Tk is that the developer has complete control, from within Tcl/Tk, of the bindings on a widget. What's even better is that the default bindings are written in Tcl/Tk, using the widget commands: they are not buried in the C code for the widget.

This has several advantages for the developer:

  • Your own bindings do not necessarily have a performance penalty over the default bindings
  • You can see exactly how the Tcl/Tk authors created their own bindings
  • You can often achieve what you want by copying the default code, and making only slight modifications

Tools for creating new sets of bindings:

  • The bindings for the text widget are in the file lib/tk*/text.tcl
  • Code to copy the bindings from the default binding tag "Text" to your own binding tag is found at Inheriting Widget Binding Classes
  • Wiki pages for bind and bindtags give essential information

Example: ntext

  • The text widget does not always behave in the same way as a modern text editor.
  • The text widget itself needs no modification: its behaviour in the GUI is determined entirely by its bindings. To remove anachronisms in the behaviour of the text widget on modern systems, only a few small adjustments to the bindings are needed.
  • The ntext package provides these adjustments.

Modified binding vs binding for changes  edit

If you want an event to fire every time the text widget changes, the <<Modified>> event might look tempting but it's not quite what you want. <<Modified>> fires when the edit modified state changes - it's most useful in conjunction with the -undo 1 flag. See the man page sections entitled "The Modified Flag" and "The Undo Mechanism".

To catch all changes to the text contents, the common trick is by wrapping the insert, delete and replace methods. See Read-only text widget and Read-only text Megawidget with TclOO for some examples using this approach. Using the same technique one can add a (sort of) -textvariable option to the widget, which is discussed elsewhere in the wiki (please add a link)

It also seems Ctext (as of 3.3) doesn't treat the modified flag and event exactly as the Tk text widget does -- see discussion on that page.

Bindings to tagged characters  edit

  • When working with text tag bindings its useful to know the Behavior of break for text tag bindings. The break command in a binding to tagged characters does not affect the execution of bindings to the widget as a whole.
  • A keyboard event can be bound to tagged characters, but the event fires only if the mouse pointer (the 'current' mark), not the text insertion cursor (the 'insert' mark) coincides with the tag: see [1] for details, and a workaround.

Some TIPs which relate to the text widget include:

  • Status: Final; Implemented in 8.4
        http://tip.tcl.tk/19  - ''obsoleted by TIP 26''
        http://tip.tcl.tk/26  ("Enhancements for the Tk Text Widget" - Undo/Redo, "Text Modified" indicator)
        http://tip.tcl.tk/93  ("Get/Delete Enhancement for the Tk Text Widget")

  • Status: Final; Scheduled for 8.5.0
        http://tip.tcl.tk/113 ("Multi-Line Searches in the Text Widget")
        http://tip.tcl.tk/155 (improving wrapped lines, scrolling etc)
        http://tip.tcl.tk/169 ("Add Peer Text Widgets")

  • Status: Draft
        http://tip.tcl.tk/167 ("Add a New Option for Context Help for [MS] Windows")
        http://tip.tcl.tk/197 ("Text Widget Persistent Cursor")

Discussion  edit

Many new features have been added to the text widget in recent releases of Tk: check that you have a current version, and check the man page for text. The feature you want may already be implemented. Version 8.5, currently in development, has further advances.

Several of the items below have been moved from Ask, and it shall be given., Ask, and it shall be given # 2, Ask, and it shall be given # 3. See those pages for questions that are not yet answered.

Bruce Hartweg writes on comp.lang.tcl:

[To move the text widget cursor to an index,] there is a special mark named insert that is used that monitors/controls where the insertion cursor is
.txtarea mark set insert 1.0

[how do I get the selection? I.E. a start and end index from a dragged selection..] there is a special tag called sel that is the current selection
.txtarea tag ranges sel

Bryan Oakley follows up with these examples:
set start [.textarea index sel.first]
set end [.textarea index sel.last]
# or...
set range [.textarea tag ranges sel]

[Nicolas Desoter] asks on comp.lang.tcl:

"Does anyone know how to print the content of a text widget in a postscript file? I need to have main layouts of the contents like character size and eventually fonts and colors. The widget contains some image too." Later he goes on to mention that the application is not available to modify, so he cannot change this into a canvas widget.

Bryan Oakley suggests checking the widget to see if the widget in question has some sort of introspective capability (like text's dump subcommand) which could be used to get the contents in a parsable format, which then could be used to recreate the widget in a hidden canvas.

Vince says he doesn't think it would be much more work just to add a 'print' subcommand to the text widget, coded in C, which makes use of the canvas widget's postscript creation C functions to do this.

Is there a way that a general solution for this sort of thing could be developed?

ulis, 2003-06-17: This seems related to Serializing a widget where you can see how to save and restore a text widget. LV, June 17, 2003: yes, that seems like a good start towards the goal.

LV 2005-06: would there be enough info in the dump to handle the printing of various character encodings? I don't know what one needs to do postscript generation of various fonts, so it's hard for me to try it out.

Lars H: Hmm... A dump of a text widget should just be a string of characters (Unicode), so there are no encodings there to worry about. The encoding problem comes when you want to generate PS code corresponding to a particular string (of Unicode characters). This is, unfortunately, very complicated, because there is very much information you need and which isn't immediately available in Tcl/Tk, but buried deep inside the windowing system (I think most systems don't even have C interfaces for getting this information, so it's not Tcl that is to blame).

What should be possible to do in pure Tcl, is to given a string and some TTF/OTF font (the actual .ttf or .otf file) generate PS code for drawing that string using that font, but it's quite a lot of work (basically writing a good part of a printer driver), and it's not necessarily what you wanted anyway.

One of the gotchas of text was recently discussed in the wiki's chatroom [add wikit reference later].

The topic was setting a variable to the contents of a text widget.

suchenwi: I think the trailing newline is obligatory in text widgets. (For saving, one often writes [$text get 1.0 end-1c] (where both 1.0 and 0.0 refer to the first character of the first line - 2.0 is the first of the second!)

lvirden: Richard, so there's always an additional newline (because I sure wouldn't want to save the data without a final newline - I've been seeing data loss here because someone's application fails to write out the last line of data if it isn't terminated.

suchenwi: Right - the bullet-proof way is to check whether the last char is a \n, and if not, append one.

lvirden: the gotcha is that the current implementation makes it difficult to determine whether the last newline was input by the user, or is being generated by the code.

suchenwi: Yes - hence test the presence. But if a user types three or five newlines after the text, the "correct" number may not be preserved. Just avoid that a text file gets longer by one \n on every save...

There doesn't seem to be much information on tags in this wiki. A short tutorial on their usage might be nice.

Dave Duxbury described in comp.lang.tcl how the Tab key can be bypassed for text widgets, so it changes widget focus instead of inserting a TAB character:
bind Text <Tab>               {continue}
bind Text <Shift-Tab>         {continue}
bind Text <Control-Tab>       {}
bind Text <Control-Shift-Tab> {}

Ro: This changes the bindings for all the text widgets. If you only want to change it for a few of the widgets, say a Read-only text widget, then use this on your widget ".t":
bind .t <Tab> {
    focus [tk_focusNext %W]
    break
}
bind .t <Shift-Tab> {
    focus [tk_focusPrev %W]
    break
}

GPS: In Tcl/Tk 8.3.4 I've discovered that deleting large amounts of text is very slow (> 30 seconds). When dealing with > 3k lines with many tags it can take quite a while. A solution that I came upon was to delete text in 40 line increments, followed by a final delete 1.0 end. I haven't been able to discover what in the Text widget's code is causing this problem, but I wanted to point this out just in case anyone else runs into it.

RS just discovered that the Tk text widget has a surprising use on Windows(NT): Copying text from IE to an Outlook message will remove linefeeds. Pasting it first into a Tk text widget, then copying it from there, and pasting it into Outlook Just Works... so Tk can even fix some Windows bugs, albeit with manual effort involved...

Question:

I have a text widget and a vertical scrollbar linked to it and new text is inserted e.g.
.a.scroll insert end "new line\n"

When lines are inserted the scrollbar will change (slider becomes shorter) but it will still show the first line. However I want the scrollbar to scroll to the bottom of the text so you could always read the last line.

RS: Easy one - after inserting text at end, add the command
.a.scroll see end

MAK: The text widget's search command directly provides most of the functionality that you'd need to implement common search dialogs - regexp support, case sensitivity, direction, etc. The one common thing it doesn't provide directly is matching on word boundaries. You can overcome this limitation fairly easily by putting your search into a loop and using the -count option, which returns the length of the matched range, and the widget's compare command with indexes using the wordstart and wordend index modifiers. Of course, you'll want to save a list of your partial matches so you know when to stop looping, since the search function automatically wraps. Pseudocode:
set partialMatches [list]
set start "insert"
set matchRange {}
while {1} {
    if {$direction == "backwards"} {
        set index "$start -1 chars"
    } else {
        set index "$start +1 chars"
    }

    # Perform search
    set start [eval $w search $switches -count length -- [list $pattern $index]]

    if {($start == "") || ([lsearch -exact $partialMatches $start] != -1)} {
        # No partial match or already saw this one
        break
    }

    # Compare matched range to word range

    set wordstart "$start wordstart"
    set wordend "$start wordend"

    if {[$w compare $wordstart == $start] && \
        [$w compare $wordend == "$start +$length chars"]} {

        # Matched whole word - store range for later use and stop.
        set matchRange [list $start $wordend]
        break
    }

    # Didn't match whole word - store start point for loop
    # checking and continue searching from there.

    lappend partialMatches $start
}

Vince comments that it does provide for searching on word-boundaries. Just use '\m' and '\M' in a regexp search pattern.

MAK: But then you have to deal with quoting hell to make sure your search pattern doesn't contain things regexp will parse as a regexp pattern if you're doing a non-regexp search. If the user wants to search for, say, [foo] (literal, not regexp), then you have to deal with quoting the brackets. (On the other hand, the above might not work, since wordstart and wordend will probably both be considered to be the first bracket, rather than the first and second, respectively). The search command could certainly use an extra switch for this. :)

Vince: I wouldn't exactly call it quoting hell in this case. A straightforward regsub does the trick:
regsub -all {[][\$?^|*+()\.\{\}\\]} $pat {\\&} pat

You call that straightforward?

Vince: Yes, I do, when the above regsub is wrapped into a proc (quote::Regfind is what I use). It seems a lot more straightforward and less error-prone than the 20 lines of pseudo-code above (which, according to the above text, might not work)!
.text search -regexp -- "\\m[quote::Regfind $word]\\M" $pos

MAK: Well, by "might not work" I meant "might not work as a user intended." To clarify: if you do a search in, say, DevStudio (and probably other MS apps) for "Foo()" and check off the "match whole word only" option, then it will not match "Foo()" even if it is in the file you're searching and it's surrounded by whitespace. Whether you'd consider that behavior wrong or a bug in DevStudio/etc. is a separate issue, but the behavior of the above pseudocode is consistent with that behavior. However, the RE method behaves that way too:
% set x "Foo()"
Foo()
% regexp {\mFoo\(\)\M} $x
0

...so the "might not work" bit applies to the RE method as well, and in the same way. It's certainly simpler number-of-lines-wise than the loop if that substitution indeed catches all of the RE syntax. Though I'm inclined to agree with the above that that pattern isn't all that straightforward. :P I find myself wondering if you've got extra backslashes in there. I do think your quoting is wrong on your .text search, though:
% regexp "\mFoo\M" "Foo"
0
% regexp {\mFoo\M} "Foo"
1

(fixed the quoting above, thanks!)

Are there any attempts out there to get a text widget to display the contents of a very large (e.g. 1 gigabyte) file in a clever incremental way (so we only show what we currently need to show, and obviously only load from disk a few pieces of the file at a time!). How about being able to edit such a huge file yet only commit the changes in one go on a 'save' operation?

ulis, 2004-01-23: If you only need to display parts of a huge file, the obvious solution is Virtuallist that virtualizes the display and can 'forget' what is no more needed.

{a m a r n r at t a t a e l x s i dot c o dot in} 2003-05-02: Hi all, I have a problem in displaying a text in Tk text widget.

Actually I am getting a string "fd6" from c function using
Tcl_SetVar(pInterp,"testfield",fd6,0);

If i print the variable fd6,I am able to get the contents of string.I want to set the contents of fd6 string to a text widget (I am able to set fd6 contents to label&entry because they have -textvariable option) I want to set contents of fd6 string to text widge(text widget doesn't have -text variable option). Please help me in this with a sample code.

[sudhi]: Say .text is ur text widget, then '.text insert end $fd6' will put your variable in the text widget. hope this helps !!

I am trying to prepare a notepad editor in which I am not able to create an Undo command. I was told that Ver. 8.4 has an inbuilt command. how do I use that?

DKF: Look at the edit subcommand of the text widget. Note that you need to turn it on to use it; it is turned off by default because many uses of thetext widget don't need this sort of thing. You could also look through the Tk demos; 8.4 includes a demonstration of how to use the undo/redo feature.

When using Tk text widgets, I've run into a weird issue with bindings: if I bind to a particular tag on the widget ($text tag bind hyperlink <ButtonPress> "do something"), then this all works fine, unless the "do something" actually creates a new toplevel window. What happens then is the new toplevel is created (on top of everything), but then the default text widget binding for <Button-1> is activated (from the original click), and now the text widget gets the focus and is moved to the front (this is on Windows).

Anyone have a good suggestion for how to stop the second binding from firing, but only under these circumstances? (I already have a 'break' in the tag binding, but that doesn't seem to affect the binding on the widget itself).

This is only an issue if you've added a <Focus> binding to the text widget which causes it to be raised. On Windows, the Tk B1 binding gives the text widget the focus, and so it's that second binding which will trigger to then raise the window

Why doesn't the text widget have a "-readonly" option like entry? -FW

KBK - Primarily for historical reasons. But it isn't at all difficult to do a Read-only text widget.

FW (much later): IMO, the answer is "there is, and it's -state disabled," being that its purpose is just the same.

Werner: I have created a text widget which contains some lines of text entry boxes in a line (see example below). Now it is possible (and how) to move the cursor between this text entry boxes, when the Up-/Down arrows keys are pressed ?
+-----------------------------------------------------+
|           .-----------. .----------. .-----------.  |
|  Track 1: |Chris Rea  | | Title 1  | |           |  |
|           `-----------' `----------' `-----------'  |
|           .-----------. .----------. .-----------.  |
|  Track 2: |Chris Rea  | | Title 2  | |           |  |
|           `-----------' `----------' `-----------'  |
:     :          :              :            :        :

e.g., if the cursor stay in the box contains "Title 1" and I press the down-key then it should be set in the text box below which contains "Title 2"..

I have no idea which Tk function can move the cursor (and input focus) between text entries.

PL: see the focus command. Also, have you considered using the TkTable widget instead?

Werner: Thanks for your hint. focus exactly does what I want. TkTable widget ? I don't know this (function ?). I use functions only from Tcl8.4/Tk8.4 Manual, BWidget and BLT extentions. Many Thanks, Werner

MSH: Try the tablelist widget. It's a text widget based metawidget which allows direct entry into the table (PURE Tcl) excellent.

PL: see Tktable for the TkTable widget. It's contained in the ActiveTcl distribution, and as it's written by Jeffrey Hobbs, the Tcl guy, it could be considered "informally standard", if there is such a phrase.

NEM 2004-01-24: Has anyone ever tried to separate the text widget internal representation (a B-Tree IIRC) from the rest of the code? This is about the only major thing I would like to see change in the text widget. For instance, I am currently writing a widget (in snit) to view/edit XML files in a simple word-processor--like view. Currently, all information is stored twice - once in the text widget, and once in a tDOM data structure. It would be really nice to be able to just tell the text widget to use the DOM tree instead of its own internal representation, i.e., having a clean separation of data and view. I looked at the code that implements the Tk text widget a while ago, but I got lost quite quickly. Anyone more knowledgeable have any good pointers as to how this might be done, or know anyone who's tried it in the past?

Vince points out that with tip#169 [2] this has actually been done to a large extent in Tk 8.5a2. It's still not as separate as you describe, but it is closer. The basic need would be to have a pluggable interface to all the TkBTree* functions in tkTextBTree.c. I think the bigger work would be providing an implementation of all of those functions for your tDOM data structure, rather than the modifications to the text widget (which would just require using a function lookup table for all access).

By the way, I think it would be a great idea, because it would also allow things like a text widget which just showed a portion of a large (gigabyte, say) file to be written relatively easily in Tcl (assuming this interface was exposed to Tcl).

See also File watch for how to alert if a file being edited in a text has changed outside the editor.

FW: Is it possible to make a tag encompass the literal beginning of the text? For instance, if I do
  .t tag add main 0.0 end
  .t tag config main -background red
on an empty text widget, the red background starts after the cursor.  Is there any way to make it so the user starts typing directly into the tag?  This is very useful if, say, you want to set the margin before someone starts typing.

KJN: I don't think this is possible, but Auto extending text widget tags shows how you can create bindings to alter tag ranges when text is entered. Similar code might deal with your problem.

KJN I've moved discussion of a problem with the Backspace and Del keys on a Sparc machine to The Backspace problem, which discusses a number of other issues with Backspace.

MJL 2006-10-03: I'm having problems deleting the last line of text from the widget. The best solution I came up with was:
.t delete "end - 2 chars - 1 lines" "end - 2 chars"

but I'm sure there must be a better way...

did you try '.t delete "end-1c linestart" "end"'?

LV 2003-03-26: Anyone have an example of how to set a minimize size on a text widget - so that it cannot be resized any smaller?

Looping over the contents of a text widget

LV hopefully, wiki regulars will fill in, here, pointers to extended text widgets such as stext.

WIBNI

  • Tk had the built-in ability to generate PDF from the text widget? It would more-or-less negate the need for a printing solution, as our apps could generate PDF and spawn an external program to print. Almost equally compelling would be to be able to take a text widget and convert it to valid html+css, but I like the idea of a single file PDF more.


jnc 2009-12-02: When getting text from the text widget it will always include a final newline, regardless if the user has entered one or not. To avoid this problem, you can simply use:
set value [.t get 1.0 "end-1 char"]

$value will now contain everything except the final newline.

MG was suprised to find recently that the default bindings for the Text widget copy hidden (elided) text, as well as visible text. The solution if you don't want this seems to be to change the tk_textCopy command to use the -displaychars option, with something like
proc tk_textCopy [info args tk_textCopy] [
    string map [list "get" "get -displaychars"] [info body tk_textCopy]]

Lihtox 2011-04-14T23:09:48:

What is the best way to set the size of a textbox in points, rather than characters? Setting the size of a textbox in pixels

xview moveto" behavior

[Daniel] 2011-06-06: Confused by the text widget documentation regarding "xview moveto". Specifically:
pathName xview moveto fraction

adjusts the view in the window so that fraction of the horizontal span of the text is off-screen to the left. Fraction is a fraction between 0 and 1."

From that description, a value of 1 should move all of the text off the screen to the left. No text should be visible. Yet, for me at least, specifying "pathname xview moveto 1" does not move 100% of the horizontal span off screen at all. Instead it just moves it as much as is needed to make the right-most element visible.

Probably a much more useful way for it to work. Still, unless I'm misreading, the documentation leads one to believe it would behave otherwise.

How to save text content when the application is closed/exited?

You cannot fire a bind script on <Destroy>. Sure you can, as the text widget is not destroyed at the very moment of invocation of the destroy-binding. However, as the text widget documentation states: the text widget is in a "half dead" state. You cannot get the contents. Instead, a
wm protocol . WM_DELETE_WINDOW {your exitproc}

must be utilized to serve the desired purpose.

See Also  edit

scrollbar