来自继承的Tkinter Text元素的不同网格行为

时间:2016-08-18 13:35:34

标签: python tkinter

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在普通视图中。根据制作新课程的布莱恩说,这些应该以完全相同的方式工作,我倾向于同意。那么为什么它们的工作方式不同呢?

1 个答案:

答案 0 :(得分:0)

这是TextWithVar中的一个错误,在这行代码中:

tk.Text.__init__(self, *args, **kwargs)

代码需要包含parent参数:

tk.Text.__init__(self, parent, *args, **kwargs)