【问题标题】:Python Tkinter: Binding Keypress Event to Active Tab in ttk.NotebookPython Tkinter:将按键事件绑定到 ttk.Notebook 中的活动选项卡
【发布时间】:2017-09-21 13:19:00
【问题描述】:

总结

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

详情

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

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

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

我正在使用 Python 3.4.3。

MCVE

这是一个最小示例,它演示了我观察到的行为。它生成一个带有五个选项卡的主窗口,每个选项卡都有一个 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()

【问题讨论】:

  • 您的代码似乎对我有用。当我按 Alt-t 时,我看到正在打印正确的数字。你是说你看到了不同的行为?
  • 是的 - 当我按下 Alt-t 时,我什么也得不到,但是当我点击按钮时,我看到了我期望看到的内容。平台重要吗?在这种情况下,我使用的是 Windows。
  • 平台可能很重要。我在ubuntu上测试过,目前无法访问windows机器。
  • 这是一个工作项目(将在 Windows 上运行)。我在家里使用 Ubuntu,今晚将测试。你使用的是什么版本的 Python/Tkinter?我想这也可能有所作为。

标签: python python-3.x tkinter ttk


【解决方案1】:

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

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

每个小部件都有一组绑定标签:与小部件同名的标签,也是小部件内部类的标签(几乎所有默认绑定都与之关联),一个标签用于顶层(或根)窗口和特殊标签“all”。因此,当您绑定到根窗口时,所有小部件都会继承此绑定,因为它们都有根窗口的绑定标记。

由于您只想在框架上触发绑定,或者当框架的任何后代具有焦点时,您可以将绑定标记添加到框架的所有子级,然后将绑定添加到该标记。

例如:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-10-30
    • 2017-01-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多