I'm trying to use the Selection event in a Text widget with modifications similar to Bryan Oakley's solution (the proxy has to be there for another feature). In the event callback I need to get the sel.last index, while the button is still clicked in order to get the selection in "real time":
import tkinter as tk
class T(tk.Text):
def __init__(self, *args, **kwargs):
tk.Text.__init__(self, *args, **kwargs)
self._orig = self._w + "_orig"
self.tk.call("rename", self._w, self._orig)
self.tk.createcommand(self._w, self._proxy)
self.bind('<<Selection>>', self._on_selection)
def _proxy(self, *args):
cmd = (self._orig,) + args
print("cmd: " + str(cmd))
return self.tk.call(cmd)
def _on_selection(self, event):
print(self.index('sel.last'))
root = tk.Tk()
text = T()
text.pack()
text.insert(tk.END, 'asdf' * 20)
root.mainloop()
The app crashes with an unhandled exception on the second click (or selection) in the Text widget (because the selection gets deleted on Button-1, before querying it in Selection):
_tkinter.TclError: text doesn't contain any characters tagged with "sel"
Now, the exception cannot be solved by handling it in the Selection event callback as the exception gets thrown in the main loop. A simple solution is to modify the _proxy method and add exception handling to the sensitive call there:
def _proxy(self, *args):
cmd = (self._orig,) + args
print("cmd: " + str(cmd))
if args[0] == 'index' and args[1] == 'sel.last':
try:
return self.tk.call(cmd)
except:
return None
else:
return self.tk.call(cmd)
My two questions:
- My solution feels a little bit hacky (and not too robust); is there a more elegant way to handle the exception further "down" on the stack (in the event)?
- How can I check (using a tkinter function) in the Selection callback whether the sel.last is accessible or not?