Python Tkinter:将按键事件绑定到 ttk.Notebook 中的活动选项卡

Python Tkinter: Binding Keypress Event to Active Tab in ttk.Notebook

总结

在 Python Tkinter 应用程序中,当使用 ttk.Notebook 时,我如何绑定按键事件,以便它仅在包含生成事件的框架的选项卡处于活动状态时触发(即,对于按钮热键,如何仅在按钮位于活动选项卡上时捕获事件?

详情

我正在编写一个 Tkinter 应用程序(我的第一个),它使用 ttk.Notebook 对象来管理界面的多个部分。我有多个选项卡,其中一些选项卡上有 "same" 按钮,但它们有不同的操作,具体取决于哪个选项卡处于活动状态(即,一个选项卡上的 "Save" 按钮保存该选项卡中的项目仅,并非来自所有选项卡)。

执行此操作的直观方法是将事件绑定到框架,然后包含 "active" 对象的框架将捕获事件,但这似乎不起作用。但是,如果我将事件绑定到根 window,则无论选项卡上下文如何,都会调用相同的处理程序。

我认为这是一个常见的要求,但我找不到有关如何执行此操作的信息。

我正在使用 Python 3.4.3.

MCVE

这是一个最小示例,它演示了我观察到的行为。它生成一个包含五个选项卡的主 window,每个选项卡都有一个 Alt-t 的事件绑定,它应该触发该选项卡中框架的事件处理程序。

import tkinter as tk
from tkinter import ttk

class MyTab(ttk.Frame):
    """Frame to be added to each tab of the notebook.

    """

    def __init__(self, master, idx, *args, **kwargs):
        super().__init__(master, *args, **kwargs)
        self._button = ttk.Button(self, text='Tab {}'.format(idx),
                                  command=lambda *args, x=idx: self._handle_button(x, *args),
                                  underline=0)
        self.bind('<Alt-t>', lambda *args, x=idx: self._handle_button(x, *args))
        self._button.pack()
        self.pack()


    def _handle_button(self, x, *args):
        print('Button: Tab {}'.format(x))



class MainWdw(ttk.Frame):
    """Main application window.

    """

    def __init__(self, master, *args, **kwargs):
        super().__init__(master, *args, **kwargs)
        self._nb = ttk.Notebook(self)

        # Generate several tabs and add a MyTab object to each.
        self._tabs = []
        for x in range(1, 6):
            t = MyTab(self, x)
            self._tabs.append(t)
            self._nb.add(t, text='Tab {}'.format(x))

        self._nb.pack(expand=1, fill='both')
        master.title('Sample')
        self.pack(expand=1, fill='both', padx=2, pady=2)



def main():
    root = tk.Tk()
    app = MainWdw(root)
    root.mainloop()



if __name__ == '__main__':
    main()

这实际上不是一个很常见的要求。大多数 GUI 不会像这样在页面之间切换。

绑定到根 window 似乎有效但绑定到框架却不起作用的原因至少部分是由于根 window 是特殊的。当您将绑定添加到小部件时,实际上并没有绑定到小部件。相反,您将绑定与 绑定标签 相关联,该标签恰好与小部件同名。

每个小部件都有一组绑定标签:与小部件同名的标签,也是小部件内部 class 的标签(几乎所有默认绑定都与之相关联) with),顶层(或根)的标签window,以及特殊标签"all"。因此,当您绑定到根 window 时,所有小部件都会继承此绑定,因为它们都有根 window.

的绑定标记

由于您只希望绑定在框架上触发,或者当框架的任何后代获得焦点时,您可以将绑定标签添加到框架的所有子级,然后将绑定添加到该标签.

例如:

class MyTab(ttk.Frame):
    def __init__(...):
        ...
        tag = str(self)
        self._add_bindtag(self, tag)
        self.bind_class(tag, '<Alt-t>', lambda *args, x=idx: self._handle_button(x, *args))

    def _add_bindtag(self, widget, tag):
        bindtags = widget.bindtags()
        if tag not in bindtags:
            widget.bindtags((tag,) + bindtags)
        for child in widget.winfo_children():
            self._add_bindtag(child, tag)

有关绑定标签的详细信息,请参阅以下答案:

绑定标签的规范 tcl/tk 文档在此处:http://tcl.tk/man/tcl8.5/TkCmd/bindtags.htm