如何在 Tkinter 中识别不可打印的 KeyPress 事件
How to identify non-printable KeyPress events in Tkinter
我正在使用多个文本小部件在 Tkinter 中制作一个应用程序,并且我正在研究 undo/redo 功能,该功能由 KeyPress 事件触发。 (我没有使用文本小部件的内置撤消堆栈,因为我有非 tkinter 对象,它也可以是 undone/redone,我想将所有内容都放在一个堆栈中)
在我开始之前,我阅读了教程和文档(例如 http://effbot.org/tkinterbook/tkinter-events-and-bindings.htm),这给我的印象是 event.char 是空的,或者 None 如果按下的键是 [=41] =] 键而不是 alphanumeric/punctuation 键。
实际情况并非如此。按键盘上的退格键(我使用的是 Macbook Air 运行 El Capitan)returns \x7f 的 event.char。
阅读有关 Tcl/TK 的更多信息,我还了解到 X keysyms 列表在平台之间并不一致,例如在我的 Mac 上,Shift 键的键符号代码显然为 0。这意味着我的应用程序将不可打印的字符(如 Delete 或 Shift 键)解释为可打印字符,这会干扰我的实现。
无论如何,我将单独处理常见的不可打印键 KeyPress 事件,但我仍然担心意外的键盘事件行为,原因有二:1) 我的程序旨在实现多平台,以及 2)使用非美式键盘的人很有可能会使用此程序。
我目前的解决方案,使用this作为参考,是检查event.keysym_num看它是否在可打印字符使用的keysym numbers/keycodes范围内。
示例代码如下:
from tkinter import *
from tkinter import ttk
root = Tk()
textbox = Text(root, width=60, height=3)
textbox.grid(sticky=(N, S, E, W))
def KeyboardEvent(event):
if event.keysym_num > 0 and event.keysym_num < 60000:
print('This is a printable key. The character is: %r keysym: %r' % \
(event.char, event.keysym_num))
else:
print('This key is unprintable. The character is: %r keysym: %r' % \
(event.char, event.keysym_num))
textbox.bind('<KeyPress>', KeyboardEvent)
root.mainloop()
我的问题:
- 我目前的方法行得通吗,或者是否有不可打印的密钥仍然会失败?
- 在 Tkinter/Python 中是否有更好的方法来区分不可打印的按键事件和可打印的按键事件? (我考虑过使用 unicodecategory 或 curses.ascii.isprint() 但每次 用户按下一个键时 都会进行此检查,所以这些看起来有点矫枉过正)
- 是否还有我应该注意的 KeyPress 事件陷阱,尤其是 Windows/Mac/Linux 之间的不一致行为? (注意:我已经知道制表符和回车符等空白字符的问题 returns)
我在 Mac 上使用 Python 3(与 Homebrew 一起安装)。谢谢!
问题 1 和 2 :
我相信你的方法有效,但使用 str.isprintable
方法似乎更简单,它 returns 一个布尔值,指示参数字符串是否可打印:
>>> "aéûβß\".isprintable() #Works with various accents, special characters
True
>>> "\x16".isprintable()
False
>>> "\n".isprintable() #Excludes all other characters
False
使用 len(repr(event.char) == 3
的方法可以工作,但它也会排除 \,它的 repr 为 4 个字符 ('\\')。
问题 3 :
就像你说的,有一堆陷阱(例如:选项卡的事件字符是“\t”,returns是“\r”...我不知道where/if您可以找到这些特殊性的详尽列表,我唯一的解决方案是尝试最常见的(例如,我键盘上的几乎每个键和组合键 Ctrl+键,当然使用程序:
chars = dict()
def LogKey(event, chars = chars): #dict is mutable
global char #get the actual value of char
dict[char] = event.char #
root = Tk()
root.bind("<KeyPress>", LogKey)
for character in "abcde...123456...²&é\"'(-è_...)": #and so on
char = character
root.event_generate("<KeyPress-{}>".format(character))
char = "<Control-{}>".format(character)
root.event_generate(char)
char = "<Control-Shift-{}>".format(character)
...
#Inspect the dictonary chars in the end
这可能不是最好的方法,但它应该涵盖大多数情况,您还可以扩展以测试多个键(例如 Control-c-v)...
我正在使用多个文本小部件在 Tkinter 中制作一个应用程序,并且我正在研究 undo/redo 功能,该功能由 KeyPress 事件触发。 (我没有使用文本小部件的内置撤消堆栈,因为我有非 tkinter 对象,它也可以是 undone/redone,我想将所有内容都放在一个堆栈中)
在我开始之前,我阅读了教程和文档(例如 http://effbot.org/tkinterbook/tkinter-events-and-bindings.htm),这给我的印象是 event.char 是空的,或者 None 如果按下的键是 [=41] =] 键而不是 alphanumeric/punctuation 键。
实际情况并非如此。按键盘上的退格键(我使用的是 Macbook Air 运行 El Capitan)returns \x7f 的 event.char。
阅读有关 Tcl/TK 的更多信息,我还了解到 X keysyms 列表在平台之间并不一致,例如在我的 Mac 上,Shift 键的键符号代码显然为 0。这意味着我的应用程序将不可打印的字符(如 Delete 或 Shift 键)解释为可打印字符,这会干扰我的实现。
无论如何,我将单独处理常见的不可打印键 KeyPress 事件,但我仍然担心意外的键盘事件行为,原因有二:1) 我的程序旨在实现多平台,以及 2)使用非美式键盘的人很有可能会使用此程序。
我目前的解决方案,使用this作为参考,是检查event.keysym_num看它是否在可打印字符使用的keysym numbers/keycodes范围内。
示例代码如下:
from tkinter import *
from tkinter import ttk
root = Tk()
textbox = Text(root, width=60, height=3)
textbox.grid(sticky=(N, S, E, W))
def KeyboardEvent(event):
if event.keysym_num > 0 and event.keysym_num < 60000:
print('This is a printable key. The character is: %r keysym: %r' % \
(event.char, event.keysym_num))
else:
print('This key is unprintable. The character is: %r keysym: %r' % \
(event.char, event.keysym_num))
textbox.bind('<KeyPress>', KeyboardEvent)
root.mainloop()
我的问题:
- 我目前的方法行得通吗,或者是否有不可打印的密钥仍然会失败?
- 在 Tkinter/Python 中是否有更好的方法来区分不可打印的按键事件和可打印的按键事件? (我考虑过使用 unicodecategory 或 curses.ascii.isprint() 但每次 用户按下一个键时 都会进行此检查,所以这些看起来有点矫枉过正)
- 是否还有我应该注意的 KeyPress 事件陷阱,尤其是 Windows/Mac/Linux 之间的不一致行为? (注意:我已经知道制表符和回车符等空白字符的问题 returns)
我在 Mac 上使用 Python 3(与 Homebrew 一起安装)。谢谢!
问题 1 和 2 :
我相信你的方法有效,但使用 str.isprintable
方法似乎更简单,它 returns 一个布尔值,指示参数字符串是否可打印:
>>> "aéûβß\".isprintable() #Works with various accents, special characters
True
>>> "\x16".isprintable()
False
>>> "\n".isprintable() #Excludes all other characters
False
使用 len(repr(event.char) == 3
的方法可以工作,但它也会排除 \,它的 repr 为 4 个字符 ('\\')。
问题 3 :
就像你说的,有一堆陷阱(例如:选项卡的事件字符是“\t”,returns是“\r”...我不知道where/if您可以找到这些特殊性的详尽列表,我唯一的解决方案是尝试最常见的(例如,我键盘上的几乎每个键和组合键 Ctrl+键,当然使用程序:
chars = dict()
def LogKey(event, chars = chars): #dict is mutable
global char #get the actual value of char
dict[char] = event.char #
root = Tk()
root.bind("<KeyPress>", LogKey)
for character in "abcde...123456...²&é\"'(-è_...)": #and so on
char = character
root.event_generate("<KeyPress-{}>".format(character))
char = "<Control-{}>".format(character)
root.event_generate(char)
char = "<Control-Shift-{}>".format(character)
...
#Inspect the dictonary chars in the end
这可能不是最好的方法,但它应该涵盖大多数情况,您还可以扩展以测试多个键(例如 Control-c-v)...