python - Tkinter 自定义条目小部件异常
问题描述
我正在尝试创建一个自定义 Tkinter Entry widget
,它将在将字符插入小部件之前将小写字符转换为大写。我知道有一些解决方案可以将按键释放事件绑定到具有获取小部件文本然后转换为大写并重新插入文本的功能的小部件。但是这些解决方案在转换发生之前显示小写字符,我不想这样做。
我正在尝试使用基于 Bryan Oakley 共享的代码的自定义条目小部件 - Tkinter 将行号添加到文本小部件
此代码非常适合自定义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
关于为什么会发生这种情况的任何想法?
解决方案
在玩弄了代码之后,我发现在条目中插入文本后,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))
否则,您可以使用完全不同的方法来更改插入文本的大小写:在条目的 textvariable 上使用跟踪。
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)
,_uppercase()
每次StringVar
更改内容时都会调用该方法。
推荐阅读
- ffmpeg - 使用带有 1 个命令的 ffmpeg 进行音频转换和过滤应用程序
- amazon-web-services - 使用 AWS API 以异步方式调用 Lambda 函数
- perl - Perl 循环中的条件和性能
- gradle - ruby 和 python 中的依赖解决方案
- python - 我如何为变量分配不同的变化,所以如果输入与分配的变量之一匹配,那么答案是正确的
- c - 读取 GPIOB_IDR 寄存器时值不正确
- java - 如何将我的 BaseAdapter 转换为 RecyclerAdapter
- javascript - 使用把手在 .hbs 文件之间进行链接的最简单方法是什么?
- javascript - 在 Chrome 扩展中将变量从 popup.js 发送到 background.js
- c++ - ServerSocket 抛出 InvalidArgumentException,但文档没有说明原因。为什么?