禁用tkinter键盘快捷键 (2)
我想继续讨论一下在禁用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 个回答
绑定的处理是有特定顺序的,这个顺序是由该控件的 bindtags
决定的。默认的顺序是:
- 具体的控件
- 控件的类别
- 顶层窗口
- 特殊类别 "all"
如果出现冲突的绑定,比如在控件和类别上都有 control-b 的绑定,它们都会按照上面说的顺序触发,除非你通过返回 "break"
来打断这个链条。
不过在你发布的代码中,你是绑定在顶层窗口(也就是根窗口)上,而冲突的绑定是在类别上。因此,类别的绑定会先被处理,然后才是顶层窗口的绑定。所以即使你的绑定返回了 "break"
,也没用,因为类别的绑定会先执行。
最简单的解决办法是把你的绑定移到具体的控件上,并返回 "break"
。这样可以确保你的绑定先执行,而 return "break"
确保类别的绑定不会被触发。
如果你真的想在根窗口上绑定,你可以使用 bind_class
方法,传入类别值 "Text"
来移除类别的绑定。
你可能会觉得 effbot.org 上的事件和绑定 页面很有用。
把你的绑定设置在文本小部件上,而不是根部件上。整个顶层的绑定会在小部件类的绑定之后处理——标准的 <Control-Key-b>
绑定就在这里——而这些又会在小部件实例的绑定之后处理,这正是你想要使用的地方。你还需要加上 'break'
; 这样可以阻止后面的绑定继续执行。(如果之后你遇到什么问题,可能是因为默认的焦点不对,但这个问题很容易解决。)
另外一个选择是重新配置绑定标签,让类绑定在顶层绑定之后处理,但这样做的后果非常微妙且影响深远;所以你最好还是按照我第一段提到的简单方法来处理,这才是正常的做法。