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
总结
在 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