Is there a way to make the Tkinter text widget read only?

It doesn't look like it has that attribute, but it'd be really useful to me.

Answers


You have to change the state of the Text widget from NORMAL to DISABLED after entering text.insert() or text.bind() :

text.config(state=DISABLED)

text = Text(app, state='disabled', width=44, height=5)

Before and after inserting, change the state, otherwise it won't update

text.configure(state='normal')
text.insert('end', 'Some Text')
text.configure(state='disabled')

The tcl wiki describes this problem in detail, and lists three possible solutions:

  1. The Disable/Enable trick described in other answers
  2. Replace the bindings for the insert/delete events
  3. Same as (2), but wrap it up in a separate widget.

(2) or (3) would be preferable, however, the solution isn't obvious. However, a worked solution is available on the unpythonic wiki:

 from Tkinter import Text
 from idlelib.WidgetRedirector import WidgetRedirector

 class ReadOnlyText(Text):
     def __init__(self, *args, **kwargs):
         Text.__init__(self, *args, **kwargs)
         self.redirector = WidgetRedirector(self)
         self.insert = self.redirector.register("insert", lambda *args, **kw: "break")
         self.delete = self.redirector.register("delete", lambda *args, **kw: "break")

Very easy solution is just to bind any key press to a function that returns "break" like so:

import Tkinter

root = Tkinter.Tk() 

readonly = Tkinter.Text(root)
readonly.bind("<Key>", lambda e: "break")

I don't have 50 reputation so I can't add a comment on nbro's answer. Nonetheless, that's where this answer belongs.

If your use case is really simple, nbro's text.bind('<1>', lambda event: text.focus_set()) code solves the interactivity problem that Craig McQueen sees on OS X but that others don't see on Windows and Linux.

OTOH, If your readonly data has any contextual structure, at some point you'll probably end up using Tkinter.Text.insert(position, text, taglist) to add it to your readonly Text box window under a tag. You'll do this because you want parts of the data to stand out based on context. Text that's been marked up with tags can be emphasized by calling .Text.tag_config() to change the font or colors, etc. Similarly, text that's been marked up with tags can have interactive bindings attached using .Text.tag_bind(). There's a good example of using these functions here. If a mark_for_paste() function is nice, a mark_for_paste() function that understands the context of your data is probably nicer.


from Tkinter import *
root = Tk()
text = Text(root)
text.insert(END,"Some Text")
text.configure(state='disabled')

Use this code in windows if you want to disable user edit and allow Ctrl+C for copy on screen text:

def txtEvent(event):
    if(event.state==12 and event.keysym=='c' ):
        return
    else:
        return "break"

txt.bind("<Key>", lambda e: txtEvent(e))

If selecting text is not something you need disabling the state is the simplest way to go. In order to support copying you can use an external entity - a Button - to do the job. Whenever the user presses the button the contents of Text will be copied to clipboard. Tk has an in-build support of handling the clipboard (see here) so emulating the behaviour of Ctrl-C is an easy task. If you are building let's say a console where log messages are written you can go further and add an Entry where the user can specify the number of log messages he wants to copy.


Need Your Help

Calculate compass bearing / heading to location in Android

android location compass-geolocation heading bearing

I want to display an arrow at my location on a google map view that displays my direction relative to a destination location (instead of north).

Explaining computational complexity theory

algorithm theory complexity-theory

Assuming some background in mathematics, how would you give a general overview of computational complexity theory to the naive?