1

GUIを動的に生成するプログラムがあります。ボタンがいくつあるかわかりません。

具体的な問題は次のようなものです。

for varname in self.filetextboxes:
    if self.varDict[varname]=='':
        self.varDict[varname] = (StringVar(),)
        self.varDict[varname][0].set('')

    fileButton = Button(self, text=" ", command = lambda:self.varDict[varname][0].set(tkFileDialog.askopenfilename()), image=self.filephoto)

    ftb = Entry(self, textvariable = self.varDict[varname][0],width=40,background='white')

テキストボックスとボタンを作成するforループがあります。StringVar()は、キーを使用して辞書に格納されますvarname

ボタンのコールバック関数で引数を渡すことができないため、代わりに各ボタンでラムダを定義します。これにより、このループで作成されたテキストボックスに関連付けられたStringVar()がファイルダイアログボックスの出力に設定されます。

問題は、ラムダに渡されるvarnameが値を渡さず、変数の名前のみを渡すことです。したがって、テキストボックスはforループで作成された変数に関連付けられていますが、ボタンのラムダは常にvarnameの現在の値を使用します。

つまり、各テキストボックスは1つの変数にのみリンクしますが、すべてのボタンは、作成された最終的なテキストボックスのテキスト、つまり、varnameの最終値を持つテキストボックスのみを設定します。

これにアプローチする別の方法はありますか?ラムダをどういうわけか、定義されたとおりにvarnameの値のみを使用し、varnameの将来の値を使用しないようにすることはできますか?

4

2 に答える 2

1

一般に、辞書を介してボタンをvarnameおよびStringVar()に関連付けます。キーはボタンのIDまたは番号であり、何でも指します。StringVarを使用しているので、Tkinterでこれを行っていると思います。辞書にアクセスする関数にボタンの番号を渡す簡単な例を次に示します。

from Tkinter import *
from functools import partial

class ButtonsTest:
   def __init__(self):
      self.top = Tk()
      self.top.title('Buttons Test')
      self.top_frame = Frame(self.top, width =400, height=400)
      self.button_dic = {}
      self.buttons()
      self.top_frame.grid(row=0, column=1)

      Button(self.top_frame, text='Exit', 
              command=self.top.quit).grid(row=10,column=1, columnspan=5)

      self.top.mainloop()

   ##-------------------------------------------------------------------         
   def buttons(self):
      b_row=1
      b_col=0
      for but_num in range(1, 11):
         ## note that the correct "but_num" is stored
         self.button_dic[but_num] = "self.cb_button_%d()" % (but_num)
         b = Button(self.top_frame, text = str(but_num), 
                    command=partial(self.cb_handler, but_num))
         b.grid(row=b_row, column=b_col)

         b_col += 1
         if b_col > 4:
            b_col = 0
            b_row += 1

   ##----------------------------------------------------------------
   def cb_button_1(self):
      print "push button 1 and this code is executed"

   ##----------------------------------------------------------------
   def cb_button_2(self):
      print "push button 2 and this code is executed"

   ##----------------------------------------------------------------
   def cb_button_3(self):
      print "push button 3 and this code is executed"

   ##----------------------------------------------------------------
   def cb_handler( self, cb_number ):
      print "cb_handler", cb_number, self.button_dic[cb_number]                
      if cb_number < 4:
         exec(self.button_dic[cb_number])

##===================================================================
BT=ButtonsTest() 
于 2012-06-11T22:32:31.133 に答える
1

私は認めなければなりません-これは私を少し困惑させます。ButtonをEntryおよびstringvarとペアリングしているため、回避策の1つは、それらを1つのクラスにまとめることです。(とにかく、これはもう少しエレガントだと言えるでしょう...)

import Tkinter as tk

class ButtonEntry(tk.Frame):
    def __init__(self,master,ss):
        tk.Frame.__init__(self)
        self.var=tk.StringVar()
        self.var.set(ss)
        self.Button=tk.Button(self,text='Button',command=lambda :self.var.set("foo!"))
        self.Entry=tk.Entry(self,textvariable=self.var)
        self.Button.grid(row=0,column=0)
        self.Entry.grid(row=0,column=1)


class App(tk.Frame):
    def __init__(self,master=None):
        tk.Frame.__init__(self,master)
        self.BEs=[]
        for i in range(10):
            b=ButtonEntry(self,'Button %d'%i)
            b.grid(row=i,column=0)
            self.BEs.append(b)


if __name__ == '__main__':
    root=tk.Tk()
    f=App(root)
    f.grid(row=0,column=0)
    root.mainloop()

ただし、ラムダがそのように動作する理由を知りたいと思います。私はあなたが持っていたものがうまくいくべきだと確信しました。

編集

ラムダ関数の動作を追跡しました。 https://stackoverflow.com/a/10452819/748858は、これを適切に行う方法の優れた例を示しています。問題は、ラムダ関数の変数が、ラムダが宣言されたスコープにまだバインドされていることです。それらをそのスコープとの関連付けを解除するには、それらを関数のキーワード引数として設定する必要があります。良い!今朝、何か新しいことを学びました。

于 2012-06-12T02:04:26.477 に答える