Python tkinter 文本修改回调 [英] Python tkinter text modified callback
问题描述
在 python 2.7 中,每当 Tkinter 文本小部件中的某些内容发生更改时,我都会尝试获取回调.
In python 2.7, I am trying to get a callback every time something is changed in the Tkinter Text widget.
该程序根据此处找到的代码使用多个帧:在 tkinter 中的两个帧之间切换
The program uses multiple frames based on code found here: Switch between two frames in tkinter
回调部分取自以下示例:http://code.activestate.com/recipes/464635-call-a-callback-when-a-tkintertext-is-modified/
The callback part is taken from the following example: http://code.activestate.com/recipes/464635-call-a-callback-when-a-tkintertext-is-modified/
这两个代码单独工作都很好,但是将这两个代码结合起来对我来说很困难.这是我尽可能使用基本代码的尝试.
Both codes work fine separately, but combining those two is difficult for me. Here is my attempt with as bare bones code as possible.
import Tkinter as tk
class Texter(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
container = tk.Frame(self)
container.pack()
self.frames = {}
for F in (ConnectPage, EditorPage):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky="nsew")
page_name = EditorPage.__name__
self.frames[page_name] = frame
self.show_frame(ConnectPage)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
def get_page(self, page_name):
return self.frames[page_name]
class ConnectPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
button1 = tk.Button(self, text="SecondPage",
command=lambda: controller.show_frame(EditorPage))
button1.grid(row=2, column=3, padx=15)
class EditorPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.text = tk.Text(self, height=25, width=80)
self.text.grid(column=0, row=0, sticky="nw")
button2 = tk.Button(self, text="FirstPage",
command=lambda: controller.show_frame(ConnectPage))
button2.grid(row=2, column=3, padx=15)
self.clearModifiedFlag()
self.bind_all('<<Modified>>', self._beenModified)
def _beenModified(self, event=None):
if self._resetting_modified_flag: return
self.clearModifiedFlag()
print("Hello!")
#self.beenModified(event)
def clearModifiedFlag(self):
self._resetting_modified_flag = True
try:
self.tk.call(self._w, 'edit', 'modified', 0)
finally:
self._resetting_modified_flag = False
if __name__ == '__main__':
gui = Texter()
gui.mainloop()
我尝试只从回调示例中提取必要的部分.当文本被修改时,代码会做一个回调(如果 self.tk.call(self._w, 'edit', 'modified', 0) 行被注释掉),但是重置修改后的标志不起作用,所以只注册第一个修改.
I tried taking only the necessary parts from the callback example. The code does do a callback (if self.tk.call(self._w, 'edit', 'modified', 0) line is commented out) when the text is modified, but resetting the modified flag does not work, so only the first modification is registered.
目前我收到以下错误:
第 67 行,在 clearModifiedFlag 中self.tk.call(self._w, '编辑', '修改', 0)_tkinter.TclError:错误的选项编辑":必须是 cget 或 configure
在回调示例代码中编辑"工作正常.
In the callback example code "edit" works fine.
这是工作代码
import Tkinter as tk
class Texter(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
container = tk.Frame(self)
container.pack()
self.frames = {}
for F in (ConnectPage, EditorPage):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky="nsew")
page_name = EditorPage.__name__
self.frames[page_name] = frame
self.show_frame(ConnectPage)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
def get_page(self, page_name):
return self.frames[page_name]
class ConnectPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
button1 = tk.Button(self, text="SecondPage",
command=lambda: controller.show_frame(EditorPage))
button1.grid(row=2, column=3, padx=15)
class EditorPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.text = CustomText(self, height=25, width=80)
self.text.grid(column=0, row=0, sticky="nw")
self.text.bind("<<TextModified>>", self.onModification)
button2 = tk.Button(self, text="FirstPage",
command=lambda: controller.show_frame(ConnectPage))
button2.grid(row=2, column=3, padx=15)
def onModification(self, event):
print("Yellow!")
class CustomText(tk.Text):
def __init__(self, *args, **kwargs):
"""A text widget that report on internal widget commands"""
tk.Text.__init__(self, *args, **kwargs)
# create a proxy for the underlying widget
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):
cmd = (self._orig, command) + args
result = self.tk.call(cmd)
if command in ("insert", "delete", "replace"):
self.event_generate("<<TextModified>>")
return result
if __name__ == '__main__':
gui = Texter()
gui.mainloop()
推荐答案
我建议采用更简单的方法.您可以为小部件设置一个代理,在该代理中,您可以检测到何时插入或删除了任何内容.您可以使用该信息生成一个虚拟事件,该事件可以像任何其他事件一样绑定.
I suggest a simpler approach. You can set up a proxy for the widget, and within that proxy you can detect whenever anything was inserted or deleted. You can use that information to generate a virtual event, which can be bound to like any other event.
让我们首先创建一个自定义文本小部件类,您将像使用任何其他文本小部件一样使用它:
Let's start by creating a custom text widget class, which you will use like any other text widget:
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)
# create a proxy for the underlying widget
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):
cmd = (self._orig, command) + args
result = self.tk.call(cmd)
if command in ("insert", "delete", "replace"):
self.event_generate("<<TextModified>>")
return result
这个例子中的代理做了三件事:
The proxy in this example does three things:
- 首先它调用实际的小部件命令,传入它收到的所有参数.
- 接下来它为每次插入和每次删除生成一个事件
- 然后它会生成一个虚拟事件
- 最后它返回实际小部件命令的结果
您可以像使用任何其他文本小部件一样使用此小部件,还有一个额外的好处,即您可以绑定到 <<TextModified>>
.
You can use this widget exactly like any other Text widget, with the added benefit that you can bind to <<TextModified>>
.
例如,如果您想在文本小部件中显示字符数,您可以执行以下操作:
For example, if you wanted to display the number of characters in the text widget you could do something like this:
root = tk.Tk()
label = tk.Label(root, anchor="w")
text = CustomText(root, width=40, height=4)
label.pack(side="bottom", fill="x")
text.pack(side="top", fill="both", expand=True)
def onModification(event):
chars = len(event.widget.get("1.0", "end-1c"))
label.configure(text="%s chars" % chars)
text.bind("<<TextModified>>", onModification)
root.mainloop()
这篇关于Python tkinter 文本修改回调的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!