在python 2.7中,每次在Tkinter Text小部件中更改某些内容时,我都会尝试进行回调。
该程序根据此处的代码使用多个框架:Switch between two frames in tkinter
回调部分取自以下示例:http://code.activestate.com/recipes/464635-call-a-callback-when-a-tkintertext-is-modified/
两个代码都可以单独使用,但是将这两个代码组合起来对我来说很难。 这是我尝试使用尽可能简单的代码。
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)行被注释掉)修改文本时,但重置修改后的flag不起作用,因此只注册了第一个修改。
目前我收到以下错误:
第67行,在clearModifiedFlag中
self.tk.call(self._w,'edit','modified',0)
_tkinter.TclError:错误选项“编辑”:必须是cget或configure
在回调示例代码中,“编辑”工作正常。
编辑:这是工作代码
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()
答案 0 :(得分:5)
我建议采用更简单的方法。您可以为窗口小部件设置代理,并且在该代理中,您可以检测何时插入或删除任何内容。您可以使用该信息生成虚拟事件,该事件可以像任何其他事件一样被绑定。
让我们首先创建一个自定义文本窗口小部件类,您将像任何其他文本窗口小部件一样使用它:
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
此示例中的代理执行三项操作:
您可以像使用任何其他文本小部件一样使用此小部件,还可以将其绑定到<<TextModified>>
。
例如,如果要在文本小部件中显示字符数,可以执行以下操作:
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()
答案 1 :(得分:1)
我在代码中集成了上面的
<<TextModified
>>示例, 工作很好,除了它干扰了一些edit_modified()
命令。幸运的是,tkinter文本窗口的文档功能不完善 效果很好,并且与
edit_modified()
get完全兼容 或设置命令:预定义的<<Modified
>>标记。你甚至都没有 要创建它,它是开箱即用的。这是我代码的相关部分:
“自我”前缀已删除,可能需要进行一些调整
将其放入“文本”小工具代码中:
title = set_title(fname, numbr)
text.bind("<<Modified>>", lambda dummy: save_indicator(title))
确保这些功能可见:
def set_title(fname, numbr):
"Creates a window title showing the save indicator,"
"the file name and a window number"
fname = strip_path(fname)
if not fname:
fname = "(New Document)"
return "+ {} - Window no.{}".format(fname, numbr)
def strip_path(fname):
return os.path.split(fname)[-1]
def save_indicator(title, event=None):
"Update the window title"
titre = toggle_star(title)
text.winfo_toplevel().title(title)
def toggle_star(title):
"Change the first character of the title"
chr='+'; chr0='x'
if text.edit_modified():
title = chr0 + title[1:]
else:
title = chr + title[1:]
return title
这是一个带有预定义
<<Modified
>>标记的完整工作示例:
def toggle_star(title):
"Change the color of the star in the title bar"
chr='+'; chr0='x'
if text.edit_modified():
title = chr0 + title[1:]
else:
title = chr + title[1:]
return title
def set_title(fname, winno):
"Put save indicator, file name and window number in the title"
if not fname:
fname = "(New Document)"
return "+ {} - Window no.{}".format(fname, winno)
def mockSave(title, event=None):
title = toggle_star(title)
root.winfo_toplevel().title(title)
text.edit_modified(0)
def read_ed_mod():
print("text.edit_modified()=", text.edit_modified())
def onModification(title, event=None):
title = toggle_star(title)
root.winfo_toplevel().title(title)
from tkinter import *
fname = 'blabla.txt'
winno = 1 ;
root = Tk()
label = Label(root, anchor="w")
text = Text(root, width=40, height=4)
label.pack(side="bottom", fill="x")
text.pack(side="top", fill="both", expand=True)
Button(root, text='Mock Save', command= lambda: mockSave(title)).pack(side=LEFT)
Button(root, text='Read ed_mod', command= lambda: read_ed_mod()).pack(side=RIGHT)
text.bind('<<Modified>>', lambda event: onModification(title))
title = set_title(fname, winno)
root.winfo_toplevel().title(title)
text.edit_modified(0)
root.mainloop()