2012-10-25 16 views
5

私は現在、カラースキームエディタを作成中です。スキームのプレビューでは、テキストウィジェットを使用します。テキストウィジェットでは、対応するカラータグ(プログラムで生成)をテキストに挿入します。私が欲しいものPython tkinter:テキストウィジェットのイベントの伝播を停止するタグ

は、次の動作です:テキストがありませんどこにでもテキストウィジェット上

  • クリック:変更の背景色
  • タグに挿入されたテキストをクリック:前景色を対応する変更タグ

は今ここに私の問題だ:

私がタグ付けされたテキストをクリックすると、タグのコールバックが呼び出されます。ここまでは順調ですね。しかし、テキスト・ウィジェットのコールバックも呼び出されますが、タグ・コールバック・メソッド(これはさらにイベント処理を停止する必要があります)で「break」を返します。 どうすればいいですか?

は、この特定の問題を説明するために、私は(Pythonの2 & 3用)本実施例を書いた:

#!/usr/bin/env python 

try: 
    from Tkinter import * 
    from tkMessageBox import showinfo 
except ImportError: 
    from tkinter import * 
    from tkinter.messagebox import showinfo 

def on_click(event, widget_origin='?'): 
    showinfo('Click', '"{}"" clicked'.format(widget_origin)) 
    return 'break' 

root = Tk() 
text = Text(root) 
text.pack() 
text.insert(CURRENT, 'Some untagged text...\n') 
text.bind('<Button-1>', lambda e, w='textwidget': on_click(e, w)) 
for i in range(5): 
    tag_name = 'tag_{}'.format(i) 
    text.tag_config(tag_name) 
    text.tag_bind(tag_name, '<Button-1>', 
     lambda e, w=tag_name: on_click(e, w)) 
    text.insert(CURRENT, tag_name + ' ', tag_name) 
root.mainloop() 

すべてのヘルプは歓迎です!

編集:Tried Python 2も同様です。

答えて

2

いいえ、 tkint 少し後ろにつまって、私は解決策を見つけ出すことができました。私は、タグはおそらくBaseWidgetからサブクラス化されていないという問題があると思います。

私の回避策:

  • は、タグの別々のコールバックを行います。ここglobalを使用して申し訳ありません(テキストウィジェットのイベントハンドラのコードで、この変数

の内容に回避策をによって何をすべきかを決定してみましょう

  • をクリックされたタグを追跡するが、変数を設定します私の質問を単純な例に変更しました...):

    #!/usr/bin/env python 
    
    try: 
        from Tkinter import * 
        from tkMessageBox import showinfo 
    except ImportError: 
        from tkinter import * 
        from tkinter.messagebox import showinfo 
    
    tag_to_handle = '' 
    
    def on_click(event, widget_origin='?'): 
        global tag_to_handle 
        if tag_to_handle: 
         showinfo('Click', '"{}" clicked'.format(tag_to_handle)) 
         tag_to_handle = '' 
        else: 
         showinfo('Click', '"{} " clicked'.format(widget_origin)) 
    
    def on_tag_click(event, tag): 
        global tag_to_handle 
        tag_to_handle = tag 
    
    root = Tk() 
    text = Text(root) 
    text.pack() 
    text.insert(CURRENT, 'Some untagged text...\n') 
    text.bind('<Button-1>', lambda e, w='textwidget': on_click(e, w)) 
    for i in range(5): 
        tag_name = 'tag_{}'.format(i) 
        text.tag_config(tag_name) 
        text.tag_bind(tag_name, '<Button-1>', 
         lambda e, w=tag_name: on_tag_click(e, w)) 
        text.insert(CURRENT, tag_name + ' ', tag_name) 
    root.mainloop() 
    

    これは同じ問題を抱えている人に役立ちます。

    私はもちろん、より良いソリューションにもオープンしています!

  • +1

    タグはテキスト固有のアイテムであり、タグクラスはありません。それらは間違いなくBaseWidgetからサブクラス化されていません。たとえば、円弧や線などのキャンバス固有のアイテムについては、同様です。ニースの回避策。 –

    2

    この質問を投稿し、解決策を提供してくれてありがとう。私はこの行動によって引き起こされた症状を修復しようとしたときに失った時間を数えられません。奇妙なTktag_bindreturn "break"には非難されています。

    tag_bindと同じイベントシーケンスとそれを結合することによってTextウィジェットを乗っ取るためにあなたのアイデアに続いて、私はがTkの相手のバインド+コールバックのペアの期待return "break"動作をシミュレートするために、今可能にするソリューションを、改善しています。アイデアは、次の(下の完全なソース)である:

    1. クラスのインスタンスは、呼び出されcallbackを実行し、その結果をチェックしたとき
    2. 、望んだcallback周りすなわち呼び出し可能なクラスのインスタンスをラッパーを作成します。
      • 結果が"break"ある場合、一時的イベントの伝播をハイジャック:bind空のコールバックと、tag_bindに結合した同じイベントにTextウィジェット。その後、アイドル時間の後、unbind
      • 結果が"break"でない場合:何もしない、イベントはここで自動的にText

    を伝播する完全な実施例です。私の具体的な問題は、ある種のハイパーテキストの動作を取得することでした。ハイパーテキストをCtrlキーを押しながらクリックすると、挿入位置がクリック位置に移動しません。以下の例では、tag_bindでラップされた同じコールバック内で、ウィジェットに、"break"または別の値を返すだけでイベントを伝播するかどうかを伝えることができます。単に__call__に渡されたeventオブジェクトからラッパコールTagBindWrapper(callback_hyper)によってTagBindWrapper("<Button-1>", callback_hyper)、すなわちイベントの情報を取得する「配列」の文字列("<Button-1>")を置き換える:

    try: 
        # Python2 
        import Tkinter as tk 
    except ImportError: 
        # Python3 
        import tkinter as tk 
    
    class TagBindWrapper: 
        def __init__(self, sequence, callback): 
         self.callback=callback 
         self.sequence=sequence 
    
        def __call__(self, event): 
         if "break" == self.callback(event): 
          global text 
          self.bind_id=text.bind(self.sequence, self.break_tag_bind) 
          return "break" 
         else: 
          return 
    
        def break_tag_bind(self, event): 
         global text 
         # text.after(100, text.unbind(self.sequence, self.bind_id)) 
         text.after_idle(text.unbind, self.sequence, self.bind_id) 
         return "break" 
    
    
    
    def callback_normal(event): 
        print "normal text clicked" 
        return "break" 
    
    def callback_hyper(event): 
        print "hyper text clicked" 
        if event.state & 0x004: # ctrl modifier 
         return "break" # will not be passed on to text widget 
        else: 
         return # will be passed on to text widget 
    
    # setup Text widget 
    root=tk.Tk() 
    text = tk.Text(root) 
    text.pack() 
    text.tag_config("normal", foreground="black") 
    text.tag_config("hyper", foreground="blue") 
    text.tag_bind("hyper", "<Button-1>", TagBindWrapper("<Button-1>", callback_hyper)) 
    text.tag_bind("normal", "<Button-1>", callback_normal) 
    
    # write some normal text and some hyper text 
    text.insert(tk.END, "normal text, ", "normal") 
    text.insert(tk.END, "hyper text (try normal-click and ctrl-click).", "hyper") 
    
    root.mainloop() 
    

    私が行う方法を見つけることができませんでした1つの簡素化があります。出来ますか?

    +0

    上記の単純化の回避策として、 'def tag_bind(textwidget、tagname、event_sequence、callback):textwidget.tag_add(タグ名、event_sequence、tagBindWrapper(event_sequence、callback))' tag_bind(テキスト、 "タグ"、 "<1>"、コールバック) '。引数を複製するのを避けるだけです。このトリックは、テキストウィジェットがTagBindWrapperクラスのコンストラクタ '__init__'の引数として与えられていれば、グローバル変数を削除することもできます –

    関連する問題