0

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:

  1. 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)?
  2. How can I check (using a tkinter function) in the Selection callback whether the sel.last is accessible or not?
newb88
  • 15
  • 5

1 Answers1

0

Finally I realized I don't necessarily have to use the 'sel.last' tag to get the actual selection before Button-1 release; I can use 'insert' instead, as the cursor is automatically moving with the mouse while the button is pressed. This way, I answered my second question which makes the first question unnecessary (or at least postpones it).

newb88
  • 15
  • 5