Python 3.x TkInter:如何获得实际的文本修改?

Python 3.x TkInter:如何获得实际的文本修改?,python-3.x,tkinter,Python 3.x,Tkinter,我想知道用户在tkinter的文本小部件中更改了什么位置和内容 我发现如何通过使用事件对文本进行修改,但无法获得实际更改: from tkinter import * def reset_modified(): global resetting_modified resetting_modified = True text.tk.call(text._w, 'edit', 'modified', 0) resetting_modified = False de

我想知道用户在tkinter的文本小部件中更改了什么位置和内容

我发现如何通过使用事件对文本进行修改,但无法获得实际更改:

from tkinter import *

def reset_modified():
    global resetting_modified
    resetting_modified = True
    text.tk.call(text._w, 'edit', 'modified', 0)
    resetting_modified = False

def on_change(ev=None):
    if resetting_modified: return
    print ("Text now:\n%s" % text.get("1.0", END))
    if False: # ???? 
        print ("Deleted [deleted substring] from row %d col %d")
    if False: # ????
        print ("Inserted [inserted substring] at row %d col %d")
    reset_modified()

resetting_modified = False
root = Tk()
text = Text(root)
text.insert(END, "Hello\nworld")
text.pack()
text.bind("<<Modified>>", on_change)
reset_modified()
root.mainloop()
例如,如果我在文本小部件中从hello\nworld中选择“ello”部分,然后按“E”,则我想查看

从第0行第1列删除[ello],然后在第0行第1列插入[E]


如果我想在运行时检测更改,是否有可能获得这些更改或至少它们的坐标,或者我基本上必须在每次击键时区分文本?

仔细研究后,我发现idlelib有一个WidgetRedirector,它可以在插入/删除事件时重定向:

from tkinter import *
from idlelib.WidgetRedirector import WidgetRedirector

def on_insert(*args):
    print ("INS:", text.index(args[0]))
    old_insert(*args)

def on_delete(*args):
    print ("DEL:", list(map(text.index, args)))
    old_delete(*args)
root = Tk()
text = Text(root)
text.insert(END, "Hello\nworld")
text.pack()
redir = WidgetRedirector(text)
old_insert=redir.register("insert", on_insert)
old_delete=redir.register("delete", on_delete)
root.mainloop()

虽然它看起来很粗糙。还有更自然的方法吗?

仔细研究后,我发现idlelib有一个WidgetRedirector,可以在插入/删除事件时重定向:

from tkinter import *
from idlelib.WidgetRedirector import WidgetRedirector

def on_insert(*args):
    print ("INS:", text.index(args[0]))
    old_insert(*args)

def on_delete(*args):
    print ("DEL:", list(map(text.index, args)))
    old_delete(*args)
root = Tk()
text = Text(root)
text.insert(END, "Hello\nworld")
text.pack()
redir = WidgetRedirector(text)
old_insert=redir.register("insert", on_insert)
old_delete=redir.register("delete", on_delete)
root.mainloop()

虽然它看起来很粗糙。还有更自然的方法吗?

捕获底层tcl/tk代码执行的低级插入和删除是实现您想要的功能的唯一好方法。您可以使用WidgetRedirector之类的工具,如果您想要更多的控制,也可以使用自己的解决方案

编写自己的代理命令以捕获所有内部命令非常简单,只需几行代码。下面是一个自定义文本小部件的示例,该小部件可以在执行每个内部命令时打印出来:

from __future__ import print_function
import Tkinter as tk

class CustomText(tk.Text):
    def __init__(self, *args, **kwargs):
        """A text widget that report on internal widget commands"""
        tk.Text.__init__(self, *args, **kwargs)

        self._orig = self._w + "_orig"
        self.tk.call("rename", self._w, self._orig)
        self.tk.createcommand(self._w, self.proxy)

    def proxy(self, command, *args):
        # this lets' tkinter handle the command as usual
        cmd = (self._orig, command) + args
        result = self.tk.call(cmd)

        # here we just echo the command and result
        print(command, args, "=>", result)

        # Note: returning the result of the original command
        # is critically important!
        return result

if __name__ == "__main__":
    root = tk.Tk()
    CustomText(root).pack(fill="both", expand=True)
    root.mainloop()

捕获底层tcl/tk代码执行的低级插入和删除是实现所需操作的唯一好方法。您可以使用WidgetRedirector之类的工具,如果您想要更多的控制,也可以使用自己的解决方案

编写自己的代理命令以捕获所有内部命令非常简单,只需几行代码。下面是一个自定义文本小部件的示例,该小部件可以在执行每个内部命令时打印出来:

from __future__ import print_function
import Tkinter as tk

class CustomText(tk.Text):
    def __init__(self, *args, **kwargs):
        """A text widget that report on internal widget commands"""
        tk.Text.__init__(self, *args, **kwargs)

        self._orig = self._w + "_orig"
        self.tk.call("rename", self._w, self._orig)
        self.tk.createcommand(self._w, self.proxy)

    def proxy(self, command, *args):
        # this lets' tkinter handle the command as usual
        cmd = (self._orig, command) + args
        result = self.tk.call(cmd)

        # here we just echo the command and result
        print(command, args, "=>", result)

        # Note: returning the result of the original command
        # is critically important!
        return result

if __name__ == "__main__":
    root = tk.Tk()
    CustomText(root).pack(fill="both", expand=True)
    root.mainloop()