2017-02-14 2 views
0

파일 선택 대화 상자를 기반으로 채워지는 옵션 메뉴가있는 창을 만들려고합니다. 이전에 선택한 파일을 기반으로 모든 옵션을 optionmenu에 포함 할 수있게되었습니다. 그러나 사용자가 어떤 옵션을 선택하든 변수에는 선택한 파일에서 마지막으로 읽은 옵션이 포함됩니다.Tkinter 옵션 메뉴 위젯 add 명령 lambda가 예상 된 명령을 생성하지 않습니다.

왜 이런 일이 일어 났는지 누군가 설명 할 수 있으면 좋겠다. 따라서, 나는 최소한의 예를 아래에 포함했다 : 코드에서 print가 예상 A, BC을 생산하면서

from Tkinter import * 
Tk() 

class App(): 

    chunks = ['A','B','C'] # These are read from a file in the actual program 
    testVariable = StringVar() 

    def __init__(self,master): 

     def initSummary(): 
      self.dataButton["menu"].delete(0, 'end') 
      for i in self.chunks: 
       print i # To demonstrate what's in there 
       self.dataButton["menu"].add_command(label=i, command = lambda: self.testVariable.set(i)) 

     top = self.top = Toplevel() 
     top.protocol("WM_DELETE_WINDOW", lambda: close(self)) 
     self.sumButton = Button(top, text="Test", width=25, command=lambda: initSummary()) 
     self.sumButton.grid(row=0, column=0, sticky=W) 
     self.dataButton = OptionMenu(top, self.testVariable, "Stuff") 
     self.dataButton.grid(row=0, column=1, sticky=W) 

# Call the main app 
root = Tk() 
app = App(root) 
root.mainloop() 

이 코드는 관계없이 사용자가 선택한 것에는 optionmenu에 C 표시됩니다. 나는 printC의 3 번을 보여 주었지만 인쇄 된 것이나 GUI에 표시된 것이 일치하지 않으면 이해할 수 있습니다.

+2

for 루프에서 람다를 사용할 때 고전적인 문제가 있습니다 : https://docs.python.org/3/faq/programming.html#why-do-lambdas-defined-in-a-loop-with-different- values-all-return-the-same-result –

+0

올바른 방향으로 나를 가르쳐 주셔서 감사합니다. @ j_4321. 위에서 언급 한 문제를 해결하기위한 중간 기능을 추가했습니다.이 문제를 해결하는 '올바른'방법이라고 생각하십니까? –

+1

이 문제를 해결하는 '올바른'방법이 있는지 나는 모른다. 나는 당신과 같은 중간 함수를 추가했지만, 이제는'lambda j = i : self.testVariable.set (j)'를 사용하는 것을 선호합니다. –

답변

-1

다음 코드와 같이 중간 기능을 추가하여 for 루프 (@ j_4321 덕분에)에서 람다 문제를 해결했습니다.

from Tkinter import * 

class App(): 

    chunks = ['A','B','C'] 

    def __init__(self,master): 

     self.testVariable = StringVar() 

     def refresh(): 
      # Prints what's in the variable 
      print self.testVariable.get() 

     def testFunc(x): 
      return lambda: self.testVariable.set(x) 

     def initSummary(): 
      self.dataButton["menu"].delete(0, 'end') 
      for i in self.chunks: 
       self.dataButton["menu"].add_command(label=i, command = testFunc(i)) 

     top = self.top = Toplevel() 
     self.sumButton = Button(top, text="Test", width=25, command=lambda: initSummary()) 
     self.sumButton.grid(row=0, column=0, sticky=W) 
     self.dataButton = OptionMenu(top, self.testVariable, "Stuff") 
     self.dataButton.grid(row=0, column=1, sticky=W) 
     self.testButton = Button(top, text="Variable", width=25, command = lambda: refresh()) 
     self.testButton.grid(row=1, column=0, sticky=W) 

# Call the main app 
root = Tk() 
app = App(root) 
root.mainloop() 

이 문제를 해결하는 데 '올바른 방법'이 아닌 경우 의견을 보내 주시기 바랍니다.

+1

'Tk() # Tkinter의 가장 큰 신비': 이것은 미스테리가 아니며 단지'testVariable = StringVar()'에 마스터 창이 필요합니다. 이것을'__init__' :'self.testVariable = StringVar()'에 넣는 것을 고려해야합니다. 그러면 클래스를 선언하기 전에 창을 만들 필요가 없습니다. –

+0

나는 항상'root - Tk()'가 마스터 윈도우를 담당 할 것으로 예상했다. 그래서 나는이 질문에 대한 예제를 만들 때 추가로'Tk()'가 필요하다는 것에 놀랐다. 이 질문을 만들었던 응용 프로그램은 언급 한대로'StringVars'가 항상'__init__' 안에 있으므로'Tk()'를 추가 할 필요가 없습니다. –

+0

@BasJansen :'Tk()'는 마스터 윈도우에 대해 _responsible_이 아니며 마스터 윈도우입니다. 두 가지를 만들면 안됩니다. –

관련 문제