与 Tk 中的大多数事件一样,您的处理程序在事件被内置绑定处理之前<Key>
触发,而不是之后。例如,这允许您阻止正常处理的发生,或更改它的作用。
但这意味着您无法访问新值(无论是通过 aStringVar
还是仅通过调用entry.get()
),因为它尚未更新。
如果您正在使用Text
,则在“修改”标志更改后会触发一个虚拟事件<<Modified>>
。假设您没有将该标志用于其他目的(例如,在文本编辑器中,您可能希望使用它来表示“启用保存按钮”),您可以使用它来完成您想要的操作:
def count(self, event=None):
if not self.post_tweet.edit_modified():
return
self.post_tweet.edit_modified(False)
self.x = len(self.post_tweet.get(1.0, END))
self.char_count.set(str(140 - self.x))
# ...
self.post_tweet.bind("<<Modified>>", self.count)
通常,当你想要这样的东西时,你想要的是Entry
a 而不是 a Text
。这提供了一种更好的方法来做到这一点:验证。与 Tkinter 基础知识之外的所有内容一样,如果不阅读 Tcl/Tk 文档(这就是 Tkinter 文档链接到它们的原因),您将无法弄清楚这一点。实际上,即使是 Tk 文档也没有很好地描述验证。但它是这样工作的:
def count(self, new_text):
self.x = len(new_text)
self.char_count.set(str(140 - self.x))
return True
# ...
self.vcmd = self.master.register(self.count)
self.post_tweet = Edit(self.master, validate='key',
validatecommand=(self.vcmd, '%P'))
可以将validatecommand
0 个或多个参数的列表传递给函数。如果您允许,该%P
参数将获取条目将具有的新值。有关更多详细信息,请参见VALIDATION
条目手册页。
如果您希望拒绝输入(例如,如果您想阻止某人输入超过 140 个字符),只需返回False
而不是True
.
顺便说一句,值得查看Tk wiki并在ActiveState上搜索 Tkinter 食谱。这是一个很好的赌注,有人有包装器,Text
并且Entry
隐藏了使这些解决方案(或其他)工作所需的所有额外内容,因此您只需要编写适当的count
方法即可。甚至可能有一个添加-style 验证的Text
包装器。Entry
还有其他几种方法可以做到这一点,但它们都有缺点。
添加一个trace
以将所有写入挂钩到StringVar
附加到您的小部件。这将被任何对变量的写入触发。我保证您第一次尝试使用它进行验证时会遇到无限递归循环问题,然后您将来会遇到其他更微妙的问题。通常的解决方案是创建一个哨兵标志,每次进入处理程序时都要检查它以确保您没有递归地执行它,然后在您执行任何可能触发递归事件的事情时设置它。(对于上面的示例,这不是必需的edit_modified
,因为我们可以忽略任何将标志设置为 的人False
,我们只将其设置为False
,因此没有无限递归的危险。)
<Key>
您可以从虚拟事件中获取新的字符(或多字符字符串) 。但是,你用它做什么呢?你需要知道它将被添加到哪里,它将被覆盖哪些字符,等等。如果你不做所有的工作来模拟Entry
- 或者更糟糕的是 -Text
编辑自己,这并不比仅仅做len(entry.get()) + 1
。