绑定到光标移动不会改变 INSERT 标记 [英] binding to cursor movement doesnt change INSERT mark

查看:13
本文介绍了绑定到光标移动不会改变 INSERT 标记的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

每次用户通过箭头、鼠标点击等更改插入点时,我都需要执行快速检查……所以我这样绑定:

I need to perform a quick check everytime the user changes the insertion point, by arrows, mouseclick, etc... so I bound it thus:

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

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

但我发现 pos 仍然是用户改变它之前的位置!我如何找到新位置(如果可能的话,一个通用的解决方案:我必须将它绑定到 home、end、pgup、pgdown,...)

but I found out that pos is still the position before the user changed it! How do I find the new position (a general solution, if possible: I have to bind it to home,end, pgup, pgdown,...)

谢谢!

推荐答案

你的方法有几个问题.一方面,您需要绑定到几乎所有内容以跟踪插入点(请记住:每次插入或删除任何内容时它都会更改).

There are several problems with your approach. For one, you'll need to bind to just about everything in order to track the insertion point (remember: it changes every time you insert or delete anything).

其次,小部件会根据类绑定发生更改,并且默认情况下,您创建的任何绑定都会在类绑定之前触发.您可以解决这些问题,但这很棘手.例如,要解决事件处理顺序,请在此站点和其他站点周围搜索绑定标签"或绑定标签".

Second, changes happen to the widget based on class bindings and, by default, any bindings you create will fire before the class bindings. You can work around these issues, but it's tricky. For example, to work around the event handling order, search around this site and others for "bind tags" or "bindtags".

然而,有一个几乎万无一失的解决方案.缺点是它需要一些严肃的 Tcl 巫术:您必须用代理替换内部小部件,该代理在插入点更改时调用回调.我在下面包含了一个完整的工作示例.

There is, however, an almost foolproof solution. The downside is that it requires some serious Tcl voodoo: you have to replace the internal widget with a proxy that calls a callback whenever the insertion point changes. I've included a complete working example, below.

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()

这篇关于绑定到光标移动不会改变 INSERT 标记的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆