首页 > 解决方案 > 处理调用代理引发的文本选择事件中的 TclError

问题描述

我正在尝试在 Text 小部件中使用 Selection 事件,其修改类似于Bryan Oakley 的解决方案(代理必须存在才能获得另一个功能)。在事件回调中,我需要获取 sel.last 索引,同时仍单击按钮以“实时”获取选择:

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()

应用程序在 Text 小部件中的第二次单击(或选择)时因未处理的异常而崩溃(因为选择在 Button-1 上被删除,然后在选择中查询它):

_tkinter.TclError: text doesn't contain any characters tagged with "sel"

现在,无法通过在选择事件回调中处理异常来解决异常,因为异常会在主循环中引发。一个简单的解决方案是修改 _proxy 方法并将异常处理添加到那里的敏感调用中:

    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)

我的两个问题:

  1. 我的解决方案感觉有点老套(而且不太健壮);有没有更优雅的方法来处理堆栈上进一步“向下”的异常(在事件中)?
  2. 如何在 Selection 回调中检查(使用 tkinter 函数) sel.last 是否可访问?

标签: tkinter

解决方案


最后我意识到在 Button-1 发布之前,我不一定非得使用 'sel.last' 标签来获得实际的选择;我可以改用“插入”,因为在按下按钮时光标会随着鼠标自动移动。这样,我回答了我的第二个问题,这使得第一个问题变得不必要(或至少推迟了它)。


推荐阅读