2016-08-18 41 views
0

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に変更します。どちらもボタンが見やすく、必要なやり方で動作します。新しいクラスを作ったブライアンによると、これらはまったく同じ方法で動作するはずです。これは私が同意する傾向があります。ではなぜ彼らは違った働きをしていますか?

答えて

0

それは、このコード行では、TextWithVarにバグです:

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

コードがparentパラメータ含める必要があります:

tk.Text.__init__(self, parent, *args, **kwargs) 
関連する問題