Somewhat surprisingly, there's nothing directly built-in to Tkinter to solve this. However, there's still a way to do what you want. The trick is to intercept all of the low level activity with the text widget, and then generate events which your app can then bind to.
For example, to get notified when the insertion cursor moves you need to generate an event whenever something is inserted or deleted, or the insertion cursor changes (via the mark set insert
command).
We can set up a proxy to intercept all of these commands. The proxy will forward the command to the original widget object, generate an event when it detects a command that would change the insertion point, and then return the result of the original command.
Here is a working example:
# for python3, use 'tkinter' instead of 'Tkinter'
import Tkinter as tk
class Example(tk.Frame):
def __init__(self, *args, **kwargs):
tk.Frame.__init__(self, *args, **kwargs)
self.text = CustomText(self, background="white")
self.status = tk.Label(self, bd=1, relief='sunken', text="", anchor="w")
self.status.pack(side="bottom", fill="x")
self.text.pack(side="right", fill="both", expand=True)
self.text.bind("<<CursorChange>>", self._on_change)
self.text.insert("end", "one\ntwo\nthree\n")
self.text.insert("end", "four\n",("bigfont",))
self.text.insert("end", "five\n")
def _on_change(self, event):
line, char = self.text.index("insert").split(".")
message = "Line: %s character: %s" % (line, char)
self.status.configure(text=message)
class CustomText(tk.Text):
def __init__(self, *args, **kwargs):
tk.Text.__init__(self, *args, **kwargs)
# create a proxy for the underlying widget
self._orig = self._w + "_orig"
self.tk.call("rename", self._w, self._orig)
self.tk.createcommand(self._w, self._proxy)
def _proxy(self, *args):
cmd = (self._orig,) + args
result = self.tk.call(cmd)
# generate an event if something was added or deleted,
# or the cursor position changed
if (args[0] in ("insert", "delete") or
args[0:3] == ("mark", "set", "insert")):
self.event_generate("<<CursorChange>>", when="tail")
return result
if __name__ == "__main__":
root = tk.Tk()
Example(root).pack(fill="both", expand=True);
root.mainloop()