9

次のブロックでは、 をクリックするa_frameとイベント ハンドラーがトリガーされますが、の子である をon_frame_clickクリックするとトリガーされません。その子で発生したイベントを強制的にトラップして処理する方法はありますか (できれば、子にハンドラーを直接追加する必要はありません)。Python 3.2.3 を使用しています。a_labela_framea_frame

import tkinter

def on_frame_click(e):
    print("frame clicked")

tk = tkinter.Tk()
a_frame = tkinter.Frame(tk, bg="red", padx=20, pady=20)
a_label = tkinter.Label(a_frame, text="A Label")
a_frame.pack()
a_label.pack()
tk.protocol("WM_DELETE_WINDOW", tk.destroy)
a_frame.bind("<Button>", on_frame_click)
tk.mainloop()
4

4 に答える 4

16

はい、やりたいことはできますが、少し手間がかかります。サポートされていないわけではありません。このようなものが必要になることは実際には非常にまれであるため、デフォルトの動作ではありません。

TL;DR-「tkinterバインドタグ」の調査

Tkinterイベントモデルには、「バインドタグ」の概念が含まれています。これは、各ウィジェットに関連付けられているタグのリストです。ウィジェットでイベントを受信すると、各バインドタグがチェックされ、イベントのバインドがあるかどうかが確認されます。その場合、ハンドラーが呼び出されます。そうでない場合は、続行します。ハンドラーが「break」を返す場合、チェーンは切断され、それ以上のタグは考慮されません。

デフォルトでは、ウィジェットのバインドタグは、ウィジェット自体、ウィジェットクラス、ウィジェットが存在するトップレベルウィンドウのタグ、そして最後に特別なタグ「all」です。ただし、そこには任意のタグを入れたり、順序を変更したりできます。

このすべての実際的な結果は?すべてのウィジェットに独自のタグを追加してから、すべてのウィジェットによって処理されるそのタグに単一のバインディングを追加できます。コードを開始点として使用する例を次に示します(これがフレームとラベルだけに特別なものではないことを示すために、ボタンウィジェットを追加しました)。

import Tkinter as tkinter

def on_frame_click(e):
    print("frame clicked")

def retag(tag, *args):
    '''Add the given tag as the first bindtag for every widget passed in'''
    for widget in args:
        widget.bindtags((tag,) + widget.bindtags())

tk = tkinter.Tk()
a_frame = tkinter.Frame(tk, bg="red", padx=20, pady=20)
a_label = tkinter.Label(a_frame, text="A Label")
a_button = tkinter.Button(a_frame, text="click me!")
a_frame.pack()
a_label.pack()
a_button.pack()
tk.protocol("WM_DELETE_WINDOW", tk.destroy)
retag("special", a_frame, a_label, a_button)
tk.bind_class("special", "<Button>", on_frame_click)
tk.mainloop()

バインドタグの詳細については、テキストウィジェットによってバインドされた後にTkinterテキストウィジェットでセルフイベントをバインドする方法についての質問に対する私の回答に興味があるかもしれません。。答えはここにあるものとは異なる質問に対処しますが、実際の問題を解決するためにバインドタグを使用する別の例を示しています。

于 2012-07-12T19:14:32.217 に答える
5

子ウィジェットに自動的にバインドする直接的な方法を見つけることはできないようですが (ただし、ウィジェットのクラス全体とアプリケーション内のすべてのウィジェットにバインドする方法はあります)、このようなものは十分に簡単です。

def bind_tree(widget, event, callback, add=''):
    "Binds an event to a widget and all its descendants."

    widget.bind(event, callback, add)

    for child in widget.children.values():
        bind_tree(child, event, callback, replace_callback)

これについて考えてみましたが、 のサイズの透明なウィジェットa_frameを の子としてすべての上に配置し、それにイベントをa_frameバインドして、必要に応じて再利用可能にするためにコールバックでas<Button>を参照することもできます。それはおそらくあなたが望むことをするでしょう。a_framee.widget.master

于 2012-07-12T17:57:28.317 に答える
0

このオンラインTkinterリファレンスの「レベルのバインド」セクションの内容に基づくと、ハンドラーを3つの異なるレベルにバインドできるため、可能であるように思われます。 要約する:

  1. インスタンスレベル:イベントを特定のウィジェットにバインドします。
  2. クラスレベル:イベントを特定のクラスのすべてのウィジェットにバインドします。
  3. アプリケーションレベル:ウィジェットに依存しない-特定のイベントは常に特定のハンドラーを呼び出します。

詳細については、最初のリンクを参照してください。

お役に立てれば。

于 2012-07-12T18:04:10.877 に答える