仅绑定 tk/tkinter 上的重要键
Bind only significant keys on tk/tkinter
能否请您告诉我是否有一种方便的方法可以仅在 tk/tkinter 的“重要”键上进行绑定?
所以,情况是我在 tk.Entry 上有一个绑定(因为我需要一个回调来在按键被按下时触发),像这样:
myEntry.bind('<Key>', ...)
现在,无论按下什么键都会触发绑定回调(即使是换档!)但我希望它只在“重要”键上触发 ...“重要”是指涉及条目中文本更改的每个键,因此“重要”键肯定是字母、数字、符号和退格键或删除键,但不是箭头键、主页、结束键、 pgUp/Down 或制表符、大写锁定、shift、ctrl 等...(我仍在考虑是否需要它在 return 键上触发,但这不是问题,因为如果我也需要它,我可以在它上面添加一个特定的绑定或者稍后在回调中忽略它)
我不知道是否有什么不同于 <Key>
我可以绑定以获得我需要的东西,是吗?
否则,如果没有,我知道我可以通过查看事件键码来了解按下了哪个键……这是要走的路吗?如果是的话,你能给我一些合适的键码间隔吗?
谢谢
这是我的解决方案,它使用 event.char
并针对包含字符的字符串进行评估(如果需要可以添加更多字符):
from tkinter import Tk, Entry
string = r"""0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"""
def key_press(event):
if event.char and event.char in string:
print(event.char)
root = Tk()
entry = Entry(root)
entry.pack()
entry.bind('<Key>', key_press)
root.mainloop()
在评论中,您说您正在对列表框进行实时过滤。为此,可以说在变量上设置跟踪而不是在条目小部件上设置绑定会更好。只有当值发生变化时才会调用跟踪,因此您不必区分是哪个键触发了变化。
这里有一个简单的例子来说明这个概念:
import tkinter as tk
widgets = [w.__name__ for w in tk.Widget.__subclasses__()]
root = tk.Tk()
entryvar = tk.StringVar()
entry = tk.Entry(root, textvariable=entryvar)
listbox = tk.Listbox(root)
entry.pack(side="top", fill="x")
listbox.pack(side="bottom", fill="both", expand=True)
listbox.insert("end", *sorted(widgets))
after_id = None
def filter_changed(*args):
global after_id
if after_id:
root.after_cancel(after_id)
# delay actual filtering slightly, in case the user is typing fast.
after_id = root.after(500, filter_listbox)
def filter_listbox(*args):
pattern = entryvar.get()
filtered_widgets = [w for w in widgets if w.startswith(pattern) ]
listbox.delete(0, "end")
listbox.insert("end", *filtered_widgets)
entryvar.trace("wu", filter_changed)
root.mainloop()
能否请您告诉我是否有一种方便的方法可以仅在 tk/tkinter 的“重要”键上进行绑定?
所以,情况是我在 tk.Entry 上有一个绑定(因为我需要一个回调来在按键被按下时触发),像这样:
myEntry.bind('<Key>', ...)
现在,无论按下什么键都会触发绑定回调(即使是换档!)但我希望它只在“重要”键上触发 ...“重要”是指涉及条目中文本更改的每个键,因此“重要”键肯定是字母、数字、符号和退格键或删除键,但不是箭头键、主页、结束键、 pgUp/Down 或制表符、大写锁定、shift、ctrl 等...(我仍在考虑是否需要它在 return 键上触发,但这不是问题,因为如果我也需要它,我可以在它上面添加一个特定的绑定或者稍后在回调中忽略它)
我不知道是否有什么不同于 <Key>
我可以绑定以获得我需要的东西,是吗?
否则,如果没有,我知道我可以通过查看事件键码来了解按下了哪个键……这是要走的路吗?如果是的话,你能给我一些合适的键码间隔吗?
谢谢
这是我的解决方案,它使用 event.char
并针对包含字符的字符串进行评估(如果需要可以添加更多字符):
from tkinter import Tk, Entry
string = r"""0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"""
def key_press(event):
if event.char and event.char in string:
print(event.char)
root = Tk()
entry = Entry(root)
entry.pack()
entry.bind('<Key>', key_press)
root.mainloop()
在评论中,您说您正在对列表框进行实时过滤。为此,可以说在变量上设置跟踪而不是在条目小部件上设置绑定会更好。只有当值发生变化时才会调用跟踪,因此您不必区分是哪个键触发了变化。
这里有一个简单的例子来说明这个概念:
import tkinter as tk
widgets = [w.__name__ for w in tk.Widget.__subclasses__()]
root = tk.Tk()
entryvar = tk.StringVar()
entry = tk.Entry(root, textvariable=entryvar)
listbox = tk.Listbox(root)
entry.pack(side="top", fill="x")
listbox.pack(side="bottom", fill="both", expand=True)
listbox.insert("end", *sorted(widgets))
after_id = None
def filter_changed(*args):
global after_id
if after_id:
root.after_cancel(after_id)
# delay actual filtering slightly, in case the user is typing fast.
after_id = root.after(500, filter_listbox)
def filter_listbox(*args):
pattern = entryvar.get()
filtered_widgets = [w for w in widgets if w.startswith(pattern) ]
listbox.delete(0, "end")
listbox.insert("end", *filtered_widgets)
entryvar.trace("wu", filter_changed)
root.mainloop()