在Python Tkinter应用程序中,当使用ttk.Notebook
时,如何绑定按键事件以便仅在包含生成事件的帧的选项卡处于活动状态时触发(即,对于按钮热键,如何执行我只在按钮处于活动标签时捕获事件?
我正在编写一个Tkinter应用程序(我的第一个),它使用ttk.Notebook
对象来管理界面的多个部分。我有多个标签,其中一些标签有"相同"它们上的按钮,但具有不同的操作,具体取决于哪个选项卡处于活动状态(即,一个选项卡上的" Save"按钮仅保存该选项卡中的项目,而不是保存所有选项卡中的项目。)
这样做的直观方法是将事件绑定到帧,然后将包含"活动"的帧绑定到帧。对象会捕获事件,但这似乎不起作用。但是,如果我将事件绑定到根窗口,则无论选项卡上下文如何,都会调用相同的处理程序。
我认为这是一个常见的要求,但我无法找到有关如何执行此操作的信息。
我使用的是Python 3.4.3。
这是一个最小的例子,它展示了我观察到的行为。它生成一个包含五个选项卡的主窗口,每个选项卡都有一个 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()
答案 0 :(得分:4)
这实际上不是一个非常常见的要求。大多数GUI不会像这样在页面之间切换。
绑定到根窗口似乎有效但绑定到框架的原因至少部分是由于根窗口是特殊的。向窗口小部件添加绑定时,您实际上并未绑定到窗口小部件。相反,您正在将绑定与绑定标记相关联,该绑定恰好与该小部件具有相同的名称。
每个小部件都会获得一组绑定标记:与小部件同名的标记,以及小部件内部类的标记(几乎所有默认绑定都与之关联),标记为顶层(或根)窗口,以及特殊标签&#34; all&#34;。因此,当您绑定到根窗口时,所有窗口小部件都会继承此绑定,因为它们都具有根窗口的绑定标记。
由于您只想在框架上触发绑定,或者当框架的任何后代具有焦点时,您可以向框架的所有子项添加绑定标记,然后向该标记添加绑定。
例如:
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