2201_75335496 2024-06-17 22:44 采纳率: 83.8%
浏览 0
已结题

py tkinter报错

我使用了一个类继承了tk.text,但是在使用idle的代码高亮时却发生了错误:

_tkinter.TclError: can't rename to ".!panedwindow.!panedwindow.!labelframe.!example.!customtext_orig": command already exists

代码:

import idlelib.colorizer as idc
import idlelib.percolator as idp

#带行数文本框实现
class TextLineNumbers(tk.Canvas):
    def __init__(self,*args, **kwargs):
        tk.Canvas.__init__(self, *args, **kwargs)
        self.textwidget = None
    def attach(self, text_widget):
        self.textwidget = text_widget
 
    def redraw(self, *args):
 
        '''redraw line numbers'''
        self.delete("all")
        # ====================self.textwidget.index("@0,0") @0,0表示最接近左上角的行信息.
        i = self.textwidget.index("@0,0")  # 找到0行0列的信息. ref: 参考文档:    https://tkdocs.com/shipman/text-index.html
        hang, lie = i.split('.')
        while True:
            dline = self.textwidget.dlineinfo(i)
            hang, lie = i.split('.')  # 计算上面i行的信息.    self.textwidget.get(i)
            debug222 = self.textwidget.get(i)  # 这里面显示滚动之后的左上角第一个字.#这时候我们读入的是1.4
            if dline is None: break  # Return tuple (x,y,width,height,baseline) giving the bounding box        and baseline position of the visible part of the line containing        the character at INDEX.
            if lie == '0':  # ===首列才画行号.
                y = dline[1]
                linenum = hang  # 行信息
                self.create_text(1, y, anchor="nw", text="{0:>2}".format(linenum),font = font)  # 创建行号. 2是x索引.
            # i = self.textwidget.index("%s+1line" % i) #然后计算下一行.
            i = self.textwidget.index(str(int(hang) + 1) + '.' + '0')  # 然后计算下一行.
        self.config(width = 50 / 4 * len(str(hang)) + 20)
class CustomText(tk.Text):
    def __init__(self,*args, **kwargs):
        tk.Text.__init__(self,*args, **kwargs,font = font,autoseparators=False, undo=True,maxundo=codeMaxUndo)
        self.config(wrap = tk.NONE)
        # 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)
        self.bind('<Key>',self.callback)
        #绑定撤回/取消撤回事件
        self.bind("<Control-KeyPress-Z>",self.undo)
        self.bind("<Control-KeyPress-Y>",self.redo)
    def undo(self,event = None):
        self.edit_undo()
    def redo(self,event = None):
        self.edit_redo()
    def callback(self,event = None):
        self.edit_separator()
    def copy(self,event = None):
        self.event_generate("<<Copy>>")
    def paste(self,event = None):
        self.event_generate("<<Paste>>")
    def cut(self,event = None):
        self.event_generate("<<Cut>>")
        
    def _proxy(self, *args): #发送自定义信号change
        # let the actual widget perform the requested action
        result=1
        try:
            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", "replace", "delete") or
                args[0:3] == ("mark", "set", "insert") or
                args[0:2] == ("xview", "moveto") or
                args[0:2] == ("xview", "scroll") or
                args[0:2] == ("yview", "moveto") or
                args[0:2] == ("yview", "scroll")
            ):
                self.event_generate("<<Change>>", when="tail")#触发change信号.
        except:
            pass
        # return what the actual widget returned
        return result
 
class Example(tk.Frame):
    def __init__(self,*args, **kwargs):
        tk.Frame.__init__(self, *args, **kwargs)
        self.text = CustomText(self)
        self.vsb = tk.Scrollbar(self, orient="vertical", command=self.text.yview)#竖直方向的滑动杆.
        self.xsb = tk.Scrollbar(self,orient = tk.HORIZONTAL,command = self.text.xview)
        self.text.configure(xscrollcommand = self.xsb.set,yscrollcommand=self.vsb.set)
        
        self.linenumbers = TextLineNumbers(self, width=30)#创建行号工具
        self.linenumbers.attach(self.text) # 绑定行号工具到text空间.
 
        self.vsb.pack(side="right", fill="y")
        self.xsb.pack(side = tk.BOTTOM,fill = tk.X)
        self.linenumbers.pack(side="left", fill="y")
        self.text.pack(side="right", fill="both", expand=True)
 
        self.text.bind("<<Change>>", self._on_change)#绑定修改到重新绘制linenumber
        self.text.bind("<Configure>", self._on_change)
        
    def _on_change(self, event):
        self.linenumbers.redraw()
    def xview(self,*args):
        CustomText.xview(*args)
......
code = Example(cf)
#code.text.bind("<Key>",highLightCode)
idc.color_config(code.text)
code.text.focus_set()
code.text.config(bg='white',fg='black')
p = idp.Percolator(code.text)
d = idc.ColorDelegator()
p.insertfilter(d)
#code.config(yscrollcommand = cscr.set)
#line.config(yscrollcommand = cscr.set)

code.pack(fill = tk.BOTH)
......
  • 写回答

3条回答 默认 最新

  • 专家-赤兔[在线] 全栈领域优质创作者 2024-06-17 22:44
    关注

    引自免费微信小程序:皆我百晓生

    遇到的问题在于CustomText类中对tk.Text的重命名操作与IDLE环境中的某些内部机制冲突。在IDLE环境中,它可能已经为tk.Text小部件定义了一些预设的命令或绑定,而你的CustomText类中的重命名尝试覆盖了这些预设,导致了TclError

    解决此问题的一种方法是在创建CustomText实例时避免重命名底层的tk.Text小部件。可以通过修改CustomText类的__init__方法来实现这一点,同时确保所有必要的功能仍然可用。下面是一种修改后的CustomText类定义,它避免了重命名问题,并保持了撤销/重做以及事件绑定的功能:

    import tkinter as tk
    
    class CustomText(tk.Text):
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs, autoseparators=False, undo=True, maxundo=100)
            self.config(wrap=tk.NONE)
            # 不再进行重命名,而是直接绑定事件和方法
            self.bind('<Key>', self.callback)
            self.bind("<Control-KeyPress-Z>", self.undo)
            self.bind("<Control-KeyPress-Y>", self.redo)
    
        def undo(self, event=None):
            self.edit_undo()
    
        def redo(self, event=None):
            self.edit_redo()
    
        def callback(self, event=None):
            self.edit_separator()
    
        # 其他方法保持不变
    

    在这个修改过的版本中,CustomText继承了tk.Text的所有属性和方法,但没有尝试重命名底层的小部件,从而避免了与IDLE或其他Tkinter应用程序的潜在冲突。所有的事件绑定和功能(如撤销、重做)都直接添加到了CustomText实例上。

    对于TextLineNumbers类和Example类,它们可以保持不变,因为它们不涉及tk.Text小部件的重命名。只需确保CustomText的定义正确,并且在Example类中正确地引用了这个更新后的CustomText类。

    这样修改后,应该能够在IDLE或其他Tkinter应用程序中正常运行你的代码,而不会遇到TclError异常。如果还有其他具体需求或问题,随时告知。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论 编辑记录
查看更多回答(2条)

报告相同问题?

问题事件

  • 系统已结题 6月25日
  • 已采纳回答 6月17日
  • 创建了问题 6月17日

悬赏问题

  • ¥15 乌班图ip地址配置及远程SSH
  • ¥15 怎么让点阵屏显示静态爱心,用keiluVision5写出让点阵屏显示静态爱心的代码,越快越好
  • ¥15 PSPICE制作一个加法器
  • ¥15 javaweb项目无法正常跳转
  • ¥15 VMBox虚拟机无法访问
  • ¥15 skd显示找不到头文件
  • ¥15 机器视觉中图片中长度与真实长度的关系
  • ¥15 fastreport table 怎么只让每页的最下面和最顶部有横线
  • ¥15 java 的protected权限 ,问题在注释里
  • ¥15 这个是哪里有问题啊?