【问题标题】:How to identify non-printable KeyPress events in Tkinter如何在 Tkinter 中识别不可打印的 KeyPress 事件
【发布时间】:2016-10-19 16:03:34
【问题描述】:

我正在使用多个 Text 小部件在 Tkinter 中制作应用程序,并且我正在开发由 KeyPress 事件触发的撤消/重做功能。 (我没有使用文本小部件的内置撤消堆栈,因为我有非 tkinter 对象,它们也可以撤消/重做,我想将所有内容保存在一个堆栈中)

在开始之前,我阅读了教程和文档(例如http://effbot.org/tkinterbook/tkinter-events-and-bindings.htm),这让我觉得如果按下的键是“特殊”键而不是字母数字/标点符号键,则 event.char 将为空或 None。

实际情况并非如此。在我的键盘上按 Backspace(我使用的是运行 El Capitan 的 Macbook Air)返回一个 event.char 为 \x7f。

阅读有关 Tcl/TK 的更多信息,我还了解到 X 键符列表在平台之间不一致,例如在我的 Mac 上,Shift 键的键符代码显然为 0。这意味着我的应用程序将不可打印的字符(如 Delete 或 Shift 键)解释为可打印字符,这会影响我的实现。

无论如何,我都会单独处理常见的不可打印键 KeyPress 事件,但我仍然担心意外的键盘事件行为,原因有两个:1)我的程序是多平台的,2)有一个使用非美国键盘的人很有可能会使用此程序。

我目前的解决方案是使用this 作为参考,检查 event.keysym_num 以查看它是否在可打印字符使用的键符编号/键码范围内。

这里是示例代码:

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() 

我的问题:

  1. 我当前的方法是否有效,或者是否有不可打印的键仍然会失效?
  2. 除了 Tkinter/Python 中的可打印键事件之外,是否有更好的方法来区分不可打印键事件? (我考虑过使用 unicodecategory 或 curses.ascii.isprint() 但此检查发生每次用户按下一个键,所以这些看起来有点过分了)
  3. 是否还有更多关于 KeyPress 事件的问题,尤其是 Windows/Mac/Linux 之间的不一致行为,我应该注意这些问题? (注意:我已经知道制表符和回车等空白字符的问题)

我在 Mac 上使用 Python 3(随 Homebrew 安装)。谢谢!

【问题讨论】:

  • if len(repr(event.char)) == 3: 呢?转换为 alt 代码的任何内容都将具有更长的表示形式,并且任何非字符的长度都为 2 ''
  • 使用键绑定执行此操作很重要,或者如果您可以在向小部件中插入或删除某些内容时获得回调,它是否同样有效?如果您要考虑不同的语言和键盘,撤消操作会很棘手。
  • @TadhgMcDonald-Jensen 我考虑过,但不确定它是否有效。 (我用过不少 Python,但没有接受过正式培训,所以不太确定 repr 是如何工作的)
  • @BryanOakley 我有这样的印象,我可能不用键绑定就可以做到,但这是我的第一个主要的 Tkinter 应用程序,一个概念证明,我正在独自开发它,所以我走上了道路- 目前的阻力最小。如果它变得足够流行以拥有非拉丁语言用户,那么我希望到那时有经验(以及时间和金钱:D)来改进它或重新开发整个事物,例如一个网络应用程序。谢谢!
  • 我不明白你的回复。我可以提供一个解决方案,在插入或删除任何内容时给你一个回调;你对那种解决方案感兴趣吗?我不知道这对你是否有用。

标签: python tkinter tk


【解决方案1】:

问题 1 和 2:

我相信您的方法有效,但仅使用 str.isprintable 方法似乎更简单,它返回一个布尔值,指示参数字符串是否可打印:

>>> "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”,返回是“\r”......我不知道在哪里/如果你能找到这些的详尽列表特殊性,我曾经有过的唯一解决方案是尝试最常见的(例如,几乎每个键和键盘上的组合键 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)...

【讨论】:

  • 关于repr("\\") 的观点非常好,我认为像"\n \r \t" 这样的字符都是空格,所以你可以使用if s.isprintable() or s.isspace():
  • 真正不可打印的键将有一个空的char 字段。
猜你喜欢
  • 2011-08-18
  • 2021-03-14
  • 2013-11-21
  • 1970-01-01
  • 2019-10-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多