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