2

ユーザーが矢印、マウスクリックなどで挿入ポイントを変更するたびに、簡単なチェックを実行する必要があるため、次のようにバインドしました。

text.bind("<Button-1>", insertchanged)

def insertchanged(event):
    pos=text.index(INSERT)
    n=text.tag_names(INSERT)
        ...

しかし、 pos はユーザーが変更するの位置のままであることがわかりました! 新しい位置を見つけるにはどうすればよいですか (可能であれば、一般的な解決策: home、end、pgup、pgdown などにバインドする必要があります)。

ありがとう!

4

2 に答える 2

6

あなたのアプローチにはいくつかの問題があります。1 つには、挿入ポイントを追跡するためにほぼすべてのものにバインドする必要があります (何かを挿入または削除するたびに変化することに注意してください)。

次に、クラス バインディングに基づいてウィジェットに変更が加えられます。デフォルトでは、作成したバインディングはクラス バインディングの前に起動します。これらの問題を回避することはできますが、注意が必要です。たとえば、イベント処理順序を回避するには、このサイトや他のサイトで「bind tags」または「bindtags」を検索してください。

ただし、ほぼ間違いのない解決策があります。欠点は、いくつかの深刻な Tcl ブードゥーが必要になることです。挿入ポイントが変更されるたびに、内部ウィジェットをコールバックを呼び出すプロキシに置き換える必要があります。以下に、完全に機能する例を示します。

import Tkinter as tk

class Example(tk.Frame):
  def __init__(self, parent):
      tk.Frame.__init__(self, parent)
      self.text = CustomText(self, wrap="word")
      self.text.pack(side="top", fill="both", expand=True)
      self.label = tk.Label(self, anchor="w")
      self.label.pack(side="bottom", fill="x")

      # this is where we tell the custom widget what to call
      self.text.set_callback(self.callback)

  def callback(self, result, *args):
      '''Updates the label with the current cursor position'''
      index = self.text.index("insert")
      self.label.configure(text="index: %s" % index)

class CustomText(tk.Text):
    def __init__(self, *args, **kwargs):
        tk.Text.__init__(self, *args, **kwargs)

        # Danger Will Robinson!
        # Heavy voodoo here. All widget changes happen via
        # an internal Tcl command with the same name as the 
        # widget:  all inserts, deletes, cursor changes, etc
        #
        # The beauty of Tcl is that we can replace that command
        # with our own command. The following code does just
        # that: replace the code with a proxy that calls the
        # original command and then calls a callback. We
        # can then do whatever we want in the callback. 
        private_callback = self.register(self._callback)
        self.tk.eval('''
            proc widget_proxy {actual_widget callback args} {

                # this prevents recursion if the widget is called
                # during the callback
                set flag ::dont_recurse(actual_widget)

                # call the real tk widget with the real args
                set result [uplevel [linsert $args 0 $actual_widget]]

                # call the callback and ignore errors, but only
                # do so on inserts, deletes, and changes in the 
                # mark. Otherwise we'll call the callback way too 
                # often.
                if {! [info exists $flag]} {
                    if {([lindex $args 0] in {insert replace delete}) ||
                        ([lrange $args 0 2] == {mark set insert})} {
                        # the flag makes sure that whatever happens in the
                        # callback doesn't cause the callbacks to be called again.
                        set $flag 1
                        catch {$callback $result {*}$args } callback_result
                        unset -nocomplain $flag
                    }
                }

                # return the result from the real widget command
                return $result
            }
            ''')
        self.tk.eval('''
            rename {widget} _{widget}
            interp alias {{}} ::{widget} {{}} widget_proxy _{widget} {callback}
        '''.format(widget=str(self), callback=private_callback))

    def _callback(self, result, *args):
        self.callback(result, *args)

    def set_callback(self, callable):
        self.callback = callable


if __name__ == "__main__":
  root = tk.Tk()
  frame = Example(root)
  frame.pack(side="top", fill="both", expand=True)
  root.mainloop()
于 2012-12-12T13:19:02.457 に答える
1

ブライアンが提案したことを行うように見えるWidgetRedirector標準ライブラリidlelibhttps://github.com/python/cpython/blob/master/Lib/idlelib/redirector.py )から使用できます。

import tkinter as tk
from idlelib.WidgetRedirector import WidgetRedirector


root = tk.Tk()
text = tk.Text(root)
text.grid()


def on_mark(*args):
    print("mark", args)
    return original_mark(*args)

def on_insert(*args):
    print("insert", args)
    return original_insert(*args)

def on_delete(*args):
    print("delete", args)
    return original_delete(*args)


redirector = WidgetRedirector(text)
original_mark = redirector.register("mark", on_mark)
original_insert = redirector.register("insert", on_insert)
original_delete = redirector.register("delete", on_delete)


root.mainloop()
于 2016-02-17T12:30:26.483 に答える