【问题标题】:Tkinter custom entry widget exceptionTkinter 自定义条目小部件异常
【发布时间】:2020-07-14 17:46:13
【问题描述】:

我正在尝试创建一个自定义 Tkinter Entry widget,它将在将字符插入小部件之前将小写字符转换为大写。我知道有一些解决方案可以将按键释放事件绑定到具有获取小部件文本然后转换为大写并重新插入文本的功能的小部件。但是这些解决方案在转换发生之前显示小写字符,我不想这样做。

我正在尝试使用基于 Bryan Oakley 共享的代码的自定义条目小部件 - Tkinter adding line number to text widget

此代码非常适合自定义 Text widget,我已在其他应用程序中使用过它。

现在我正在尝试使用相同的方法来创建自定义条目小部件。这是包含自定义文本小部件和自定义条目小部件的示例代码:

from tkinter import *

class CustomText(Text):
    def __init__(self, *args, **kwargs):
        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)

    def _proxy(self, *args):

        if args[0] == "insert" and args[1] == "insert":
           args =('insert', 'insert', args[2].upper())

        cmd = (self._orig,) + args
        result = self.tk.call(cmd)
        return result

class CustomEntry(Entry):
    def __init__(self, *args, **kwargs):
        Entry.__init__(self, *args, **kwargs)

        self._orig = self._w + "_orig"
        self.tk.call("rename", self._w, self._orig)
        self.tk.createcommand(self._w, self._proxy)

    def _proxy(self, *args):

        if args[0] == "insert" and args[1] == "insert":
           args =('insert', 'insert', args[2].upper())

        cmd = (self._orig,) + args
        result = self.tk.call(cmd)
        return result

def get_text():
    print("TEXT widget text = ", mytext.get("1.0", "end"))
    print("ENTRY widget text = " ,entryvar.get())

root = Tk()

entryvar = StringVar()

root.geometry("300x300")
myframe = Frame(root, width = 300, height = 300)
Label(myframe, text="TEXT WIDGET").pack(side = TOP)
myframe.pack(side = TOP)
mytext = CustomText(myframe, width = 30, height=1, wrap="none")
mytext.pack(side = TOP)
Label(myframe, text="ENTRY WIDGET").pack(side = TOP)
myentry = CustomEntry(myframe,  textvariable=entryvar, width = 30)
myentry.pack(side = TOP)

Button(myframe, text="Get Entry Widget Text", command=get_text).pack(side=TOP)

root.mainloop()

该解决方案适用于 CustomText 小部件。如您所见,字符在插入之前进行了转换,结果就像用户在按下 shift 键时输入字符一样。

但是在将数据输入CustomEntry 小部件时出现异常,我从result = self.tk.call(cmd) 中得到以下异常:

Traceback (most recent call last):
  File "C:/Users/rhkea/AppData/Roaming/JetBrains/PyCharmCE2020.1/scratches/custom_entry_box.py", line 57, in <module>
    root.mainloop()
  File "C:\Users\rhkea\AppData\Local\Programs\Python\Python37\lib\tkinter\__init__.py", line 1283, in mainloop
    self.tk.mainloop(n)
  File "C:/Users/rhkea/AppData/Roaming/JetBrains/PyCharmCE2020.1/scratches/custom_entry_box.py", line 34, in _proxy
    result = self.tk.call(cmd)
_tkinter.TclError: selection isn't in widget .!frame.!customentry

关于为什么会发生这种情况的任何想法?

【问题讨论】:

  • 请不要发布堆栈跟踪的图片。它们不可搜索,视障者根本无法阅读。
  • 好的 - 更改为将异常显示为文本。
  • 最好包含整个堆栈跟踪。

标签: python tkinter widget


【解决方案1】:

在玩弄了代码之后,我发现在条目中插入文本后,方法index sel.first被调用了。但是没有选择,因此会引发错误“选择不在小部件.!frame.!customentry 中”。我不知道这是如何在常规 Entry 中处理的,但你可以发现这个错误:

class CustomEntry(Entry):
    def __init__(self, *args, **kwargs):
        Entry.__init__(self, *args, **kwargs)

        self._orig = self._w + "_orig"
        self.tk.call("rename", self._w, self._orig)
        self.tk.createcommand(self._w, self._proxy)

    def _proxy(self, *args):
        if args[0] == "insert" and args[1] == "insert":
            args = ('insert', 'insert', args[2].upper())
        cmd = (self._orig,) + args

        try:
            return self.tk.call(cmd)
        except TclError as e:
            if args[0] == 'index' and args[1] == 'sel.first':
                pass
            else:
                raise TclError(str(e))

否则,您可以使用完全不同的方法来更改插入文本的大小写:在条目的文本变量上使用跟踪。

class CustomEntry(Entry):
    def __init__(self, *args, **kwargs):
        Entry.__init__(self, *args, **kwargs)
        self._var = StringVar(self)
        self.configure(textvariable=self._var)
        self._var.trace_add('write', self._uppercase)

    def _uppercase(self, *args):
        self._var.set(self._var.get().upper())

使用self._var.trace_add('write', self._uppercase),每次StringVar的内容发生变化时都会调用_uppercase()方法。

【讨论】:

    猜你喜欢
    • 2020-11-22
    • 2022-12-20
    • 2011-06-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多