禁用tkinter键盘快捷键 (2)

3 投票
2 回答
1759 浏览
提问于 2025-04-16 22:12

我想继续讨论一下在禁用tkinter快捷键中提到的内容:我有一个事件处理程序,它和Tkinter使用的事件冲突,所以我的程序和Tkinter的互动很糟糕。

因为这个问题我一直没法解决,所以我在这里重新提出来,试着把它简化到最基本的形式,代码如下:

#!/usr/bin/env python

from Tkinter import *
import tkFont

def init():
    global root,text

    root = Tk()
    root.geometry("500x500+0+0")
    dFont=tkFont.Font(family="Arial", size=10)

    text=Text(root, width=16, height=5, font=dFont)
    text.pack(side=LEFT, fill=BOTH, expand = YES)

    root.bind("<Control-b>", setbold)

    text.tag_config("b",font=('Verdana', '10', 'bold' ))
    text.tag_config("i",font=('Verdana', '10', 'italic' ))

def removeformat(event=None):
    text.tag_remove('b',SEL_FIRST,SEL_LAST)
    text.tag_remove('i',SEL_FIRST,SEL_LAST)

def setbold(event=None):
    removeformat()
    text.tag_add('b', SEL_FIRST,SEL_LAST)
    text.edit_modified(True)

def main():
    init()        
    mainloop()


if __name__ == '__main__':
    main()

这个程序应该做的就是打开一个文本窗口,让你可以在里面输入文字。选中一些文字后按下Ctrl+B,程序应该去掉之前的标签,然后给选中的文字加上一个'b'标签,让文字变成粗体。

但实际上发生的情况是,在第一次调用tag_remove时出现了一个错误,提示我文本中没有带“sel”标签的字符

有人建议使用return 'break',但这没什么用,因为在setbold()有机会执行之前,选中的内容就消失了……

2 个回答

3

绑定的处理是有特定顺序的,这个顺序是由该控件的 bindtags 决定的。默认的顺序是:

  1. 具体的控件
  2. 控件的类别
  3. 顶层窗口
  4. 特殊类别 "all"

如果出现冲突的绑定,比如在控件和类别上都有 control-b 的绑定,它们都会按照上面说的顺序触发,除非你通过返回 "break" 来打断这个链条。

不过在你发布的代码中,你是绑定在顶层窗口(也就是根窗口)上,而冲突的绑定是在类别上。因此,类别的绑定会先被处理,然后才是顶层窗口的绑定。所以即使你的绑定返回了 "break",也没用,因为类别的绑定会先执行。

最简单的解决办法是把你的绑定移到具体的控件上,并返回 "break"。这样可以确保你的绑定先执行,而 return "break" 确保类别的绑定不会被触发。

如果你真的想在根窗口上绑定,你可以使用 bind_class 方法,传入类别值 "Text" 来移除类别的绑定。

你可能会觉得 effbot.org 上的事件和绑定 页面很有用。

4

把你的绑定设置在文本小部件上,而不是根部件上。整个顶层的绑定会在小部件类的绑定之后处理——标准的 <Control-Key-b> 绑定就在这里——而这些又会在小部件实例的绑定之后处理,这正是你想要使用的地方。你还需要加上 'break'; 这样可以阻止后面的绑定继续执行。(如果之后你遇到什么问题,可能是因为默认的焦点不对,但这个问题很容易解决。)

另外一个选择是重新配置绑定标签,让类绑定在顶层绑定之后处理,但这样做的后果非常微妙且影响深远;所以你最好还是按照我第一段提到的简单方法来处理,这才是正常的做法。

撰写回答