In another answer here、ユーザはTkinter.Text要素のインスタンスを提供するが、Tkinter.Entryのようなテキスト変数機能を持つ継承TextWithVarクラスを作成しました。ただし、テストでは、この新しいクラスは、Gridマネージャを使用するときにTextエレメントとは異なる動作をします。実証するために、このコードはその答えからコピーされ、最後にいくつかのテストコールを添加した:TextWithVar要素がルート内に直接あるときに、この例では継承されたTkinterのテキストエレメントと異なるグリッド動作
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()
、それはそれのように働くべきである - ボタン要素が角の上に配置されます。しかし、両方がフレーム内にある場合、Button要素はどこにも見えません。 TextWithVarの両方の呼び出しをtk.Textに変更します。どちらもボタンが見やすく、必要なやり方で動作します。新しいクラスを作ったブライアンによると、これらはまったく同じ方法で動作するはずです。これは私が同意する傾向があります。ではなぜ彼らは違った働きをしていますか?