Python Tkinter: привязка события нажатия клавиши к активной вкладке в ttk.Тетрадь
резюме
в приложении 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()
1 ответов
Это на самом деле не очень распространенное требование. Большинство GUI не переключаются между страницами, как это.
причина, по которой привязка к корневому окну, кажется, работает, но привязка к фрейму не происходит, по крайней мере, частично из-за того, что корневое окно является специальным. При добавлении привязки к виджету вы фактически не привязываетесь к виджету. Вместо этого вы связываете привязку с привязки тег это происходит с тем же именем, что и виджет.
каждый виджет получает набор тегов привязки: тег с тем же именем, что и виджет, но также тег для внутреннего класса виджета (с которым связаны почти все привязки по умолчанию), тег для окна верхнего уровня (или корневого) и специальный тег "все". Таким образом, при привязке к корневому окну, все виджеты наследуют эту привязку, поскольку все они имеют тег привязки для корневого окна.
Так как вы хотите, чтобы привязка срабатывала только на кадре или когда-либо потомок кадра имеет фокус, вы можете добавить тег привязки ко всем дочерним элементам кадра, а затем добавить привязку к этому тегу.
например:
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