In another answer here,用户创建了一个继承的TextWithVar类,它提供了Tkinter.Text元素的实例,但具有像Tkinter.Entry一样的文本变量功能。但是,在测试中,当使用网格管理器时,这个新类的行为与Text元素不同。为了演示,此代码是从该答案中复制的,最后添加了一些测试调用:
import Tkinter as tk
class TextWithVar(tk.Text):
'''A text widget that accepts a 'textvariable' option'''
def __init__(self, parent, *args, **kwargs):
try:
self._textvariable = kwargs.pop("textvariable")
except KeyError:
self._textvariable = None
tk.Text.__init__(self, *args, **kwargs)
# if the variable has data in it, use it to initialize
# the widget
if self._textvariable is not None:
self.insert("1.0", self._textvariable.get())
# this defines an internal proxy which generates a
# virtual event whenever text is inserted or deleted
self.tk.eval('''
proc widget_proxy {widget widget_command args} {
# call the real tk widget command with the real args
set result [uplevel [linsert $args 0 $widget_command]]
# if the contents changed, generate an event we can bind to
if {([lindex $args 0] in {insert replace delete})} {
event generate $widget <<Change>> -when tail
}
# return the result from the real widget command
return $result
}
''')
# this replaces the underlying widget with the proxy
self.tk.eval('''
rename {widget} _{widget}
interp alias {{}} ::{widget} {{}} widget_proxy {widget} _{widget}
'''.format(widget=str(self)))
# set up a binding to update the variable whenever
# the widget changes
self.bind("<<Change>>", self._on_widget_change)
# set up a trace to update the text widget when the
# variable changes
if self._textvariable is not None:
self._textvariable.trace("wu", self._on_var_change)
def _on_var_change(self, *args):
'''Change the text widget when the associated textvariable changes'''
# only change the widget if something actually
# changed, otherwise we'll get into an endless
# loop
text_current = self.get("1.0", "end-1c")
var_current = self._textvariable.get()
if text_current != var_current:
self.delete("1.0", "end")
self.insert("1.0", var_current)
def _on_widget_change(self, event=None):
'''Change the variable when the widget changes'''
if self._textvariable is not None:
self._textvariable.set(self.get("1.0", "end-1c"))
root = tk.Tk()
text_frame = TextWithVar(root)
text_frame.grid(row=1, column=1)
test_button = tk.Button(root, text='Test')
test_button.grid(row=1, column=1, sticky='NE')
root.mainloop()
root2 = tk.Tk()
frame = tk.Frame(root2)
frame.grid(row=1, column=1)
text_frame2 = TextWithVar(frame)
text_frame2.grid(row=1, column=1)
test_button2 = tk.Button(frame, text='Test')
test_button2.grid(row=1, column=1, sticky='NE')
root2.mainloop()
在这个例子中,当TextWithVar元素直接位于root内部时,它就像它应该的那样 - 将Button元素放在角落的顶部。但是,当两者都在Frame内时,Button元素无处可见。现在将TextWithVar调用更改为tk.Text。它们都以他们应该的方式工作,Button在普通视图中。根据制作新课程的布莱恩说,这些应该以完全相同的方式工作,我倾向于同意。那么为什么它们的工作方式不同呢?
答案 0 :(得分:0)
这是TextWithVar
中的一个错误,在这行代码中:
tk.Text.__init__(self, *args, **kwargs)
代码需要包含parent
参数:
tk.Text.__init__(self, parent, *args, **kwargs)