Tkinter 中冲突的默认绑定和用户定义绑定之间的优先级依赖事件更改

问题描述 投票:0回答:1

我有一个带有 Tkinter 的 Python GUI。在一堂课中,我有一些文本小部件。这些有一些default bindings其中一些我想最好用

bind_class()
替换。除了那些带有大写热键的热键,例如
Ctrl-E/A/B/F
(即
Ctrl-Shift-e/a/b/f
),我设法做到了。这些我只能通过分别在每个小部件上应用
bind()
方法来更改。我想知道为什么会这样,如果有更聪明的方法来使用
bind_class()
来做到这一点,否则它似乎对上述默认绑定没有影响。

请考虑以下代码。单击每个文本小部件并尝试所有四个热键 (

Ctrl-b/B/y/Y
) 后,可以看到它们都按预期在两个小部件中工作,除了
Ctrl-B
(即
Ctrl-Shift-b
),它只有在绑定时才有效使用
bind()
.

到小部件

我现在看到这个问题:对于带有大写 Key 的内置函数,优先顺序显然如下:

bind()
> 带有
return 'break'
的内置函数可能 >
bind_class()
。这意味着,如果
bind_class()
中引用的函数末尾没有
return 'break'
,那么
bind()
将永远不会工作,并且只会调用内置函数。同时,带有小写键的内置热键(例如
Ctrl-a/e/b/f
)在某种程度上具有较低的优先级,甚至
bind_class()
甚至可以优先于它们。

所以我的问题是:

  1. 我上面的结论是正确的,还是另有隐情?
  2. 这是
    bind()
    bind_class()
    的预期功能吗?
  3. 是否仍然有可能以某种方式覆盖像
    Ctrl-B
    这样的内置函数,一次只对所有小部件使用
    bind_class()
    ,而不是一个接一个地对它们进行
    bind()

欢迎任何有见地的评论。谢谢!

from tkinter import *

class Test:
    def __init__(self):
        self.window = Toplevel(root)
        self.window.lift()
        
        self.t1 = Text(self.window)
        self.t1.insert(1.0, 'Initial text in Text widget #1')
        #self.t1.bind('<Control-B>', self.func)
        self.t1.pack()
        
        self.t2 = Text(self.window)
        self.t2.insert(1.0, 'Initial text in Text widget #2')
        self.t2.bind('<Control-B>', self.func)
        self.t2.pack()
        
        self.t1.bind_class('Text', '<Control-b>', self.func)
        self.t1.bind_class('Text', '<Control-B>', self.func)   # This line has no effect.
        
        self.t1.bind_class('Text', '<Control-y>', self.func)
        self.t1.bind_class('Text', '<Control-Y>', self.func)
    
    def func(self, event):
        obj = root.focus_get()
        obj.insert(END, '\n'+str(event))
        return 'break'

root = Tk()
t1 = Test()
root.lower()
root.mainloop()
python python-3.x tkinter bind tk-toolkit
1个回答
0
投票

优先顺序不会改变,在所有情况下对于所有小部件都是相同的,并且始终由小部件的绑定标签定义。所以,回答你的前几个问题:不,你的结论不正确,是的,这是按设计工作的。

这种情况下的问题是,至少在某些平台上,

<Control-Shift-Key-B>
与虚拟事件
<<SelectPrevChar>>
相关联。当您按下 control+B 时,事件会在传递给小部件之前转换为
<<SelectPrevChar>>
虚拟事件。类绑定是针对该事件而不是原始按键。换句话说,小部件永远不会看到
<Control-Shift-Key-B>
,它只会看到
<<SelectPrevChar>>
.

您可以通过以下两种方式之一解决此问题:

  • 您可以删除虚拟事件,在这种情况下您的类绑定将起作用
  • 您可以更改虚拟事件的类绑定

要删除虚拟事件并向原始事件序列添加显式绑定,您可以这样做:

self.window.event_delete("<<SelectPrevChar>>")
self.t1.bind_class("Text", "<Control-Shift-Key-B>", self.func)

要更改虚拟事件的类绑定,您可以在虚拟事件上使用

bind_class

self.t1.bind_class("Text", "<<SelectPrevChar>>", self.func)

要查看所有虚拟事件的列表以及它们绑定到的键,您可以运行这段代码,它使用不带参数的

event_info
命令来获取虚拟事件列表,然后使用相同的方法获取有关每个事件的信息。

for event in self.window.event_info():
    info = self.window.event_info(event)
    print(f"{event:<20s} => {', '.join(info)}")

© www.soinside.com 2019 - 2024. All rights reserved.