2016-08-11 4 views
0

私はPythonのtkinterモジュールを初めて使用しているので、何か助けてくれてありがとうと思っています。lambdaコマンドを使用するとPython tkinter NameErrorが発生する

私は、フォームの4タプルのリストを持っています(foo, bar, x, y);このような何か:理想的な機能を有する各ボタンで、テキストbarとボタンとして変数をインスタンス化しfoo

TUPLE_LIST = [('Hello', 'World', 0, 0), 
        ('Hovercraft', 'Eels', 50, 100), 
        etc.] 

以降forループは、それぞれにbarがすでに定義されたその場所をEntryウィジェットを追加しますそれ座標x, yで:

for foo, bar, x, y in TUPLE_LIST: 
     exec("{0} = Button(self, text='{1}', command=lambda: self.update_text('{1}'))".format(foo, bar)) 
     eval(name).place(x=x, y=y) 

ボタンが完全に置くが、私はそれらのいずれかをクリックして行けば、私は次のエラーを取得:

 Traceback (most recent call last): 
     File "...\lib\tkinter\__init__.py", line 1550, in __call__ 
     return self.func(*args) 
     File "<string>", line 1, in <lambda> 
    NameError: name 'self' is not defined 

これは、コマンドがラムダで定義されているため、定義された「関数」ではないということが関係していると思いますが、ラムダとのコマンド。それではexecも使用するのですか? (それが重要な場合)。また、ここではupdate_textのためのコードは次のとおりです。

def update_text(self, new_char): 
     old_str = self.text_box_str.get() 
     # Above is a StringVar() defined in __init__ and used as textvariable in Entry widget creation. 
     self.text_box_str.set(old_str + new_char) 

すべてのヘルプははるかに高く評価されるだろう。前もって感謝します。

答えて

1

これは非常に悪い考えです。変数名を動的に作成するには、単純に乾くべき理由はありません。コードが複雑になり、保守が難しくなり、読みにくくなります。

あなたは辞書を使用、名前でウィジェットを参照する場合:selfでの問題については

buttons = {} 
for foo, bar, x, y in TUPLE_LIST: 
    buttons[foo] = Button(self, text=bar, ...) 
    buttons[foo].place(...) 

を、問題が何であるかを言うために十分なコードはありません。クラスを使用している場合、コードは大丈夫です。そうでない場合は、selfを使用するべきではありません。

ウィジェットを更新する関数を作成するには、ウィジェットまたはそのウィジェットの名前を関数に渡すだけです。どのウィジェットを更新したいかははっきりしていません。これはエントリウィジェットのようです。すべてのボタンを更新する必要があるエントリウィジェットが1つあるか、ボタンごとに1つのエントリウィジェットがあるかどうかはわかりません。私は前者を仮定します。

次の例では、変更する変数と追加するテキストを関数に渡す方法を示します。このソリューションでは、textvariable属性は使用しませんが、必要に応じて使用できます。ちょうどウィジェットではなく、それを渡す。もちろん

buttons[foo] = Button(..., command=lambda widget=self.text_box, value=bar: self.update_text(widget, value)) 
... 
def update_text(self, widget, value): 
    old_value = widget.get() 
    new_value = old_value + value 
    widget.delete(0, "end") 
    widget.insert(0, new_value) 

、あなたがやっているすべての文字列を追加している場合、あなたは十分公正、widget.insert("end", value)

+0

OKで、これらの4行を置き換えることができますが、それはまだ元の問題を解決していません。どうすればこれらのボタンを作成して、それぞれの 'bar'を' Entry'ウィジェットに追加する 'コマンド'を持つようにできますか?なぜなら、 'exec'呼び出しで文字列フォーマット以外のことをする方法は考えられないからです。それが問題を引き起こしていたようです。そして、はい、私はクラスを使っています(しかし、問題を引き起こしていた「自己」は私のものでさえありませんでした)。 – ENPM

+0

@ENPM:構築された文字列で 'exec'を呼び出すことに頼らざるを得ません。関数を呼び出して更新するウィジェットを渡す方法を示すために私の答えを更新しました。この関数はウィジェットの名前を知る必要はなく、ウィジェット自体への参照を与えることができます。 –

+0

OK、ありがとう!私はその代わりに行くだろう。 – ENPM

関連する問題