2012-06-02 9 views
18

Tôi đang cố gắng tạo các nút trong tkinter trong vòng lặp for. Và với mỗi vòng lặp vượt qua giá trị i đếm như một đối số trong giá trị lệnh. Vì vậy, khi hàm được gọi từ giá trị lệnh, tôi có thể cho biết nút nào đã được nhấn và hành động tương ứng. Vấn đề là, cho phép len là 3, nó sẽ tạo ra 3 nút với tiêu đề "Game 1" thông qua "Game 3" nhưng khi bất kỳ nút nào được nhấn thì giá trị in luôn là 2, lần lặp cuối cùng. Vì vậy, nó xuất hiện các nút đang được thực hiện như là các thực thể riêng biệt, nhưng giá trị i trong các đối số lệnh có vẻ giống nhau. Đây là mã:Tạo các nút tkinter bằng Python cho các đối số lệnh vòng lặp

def createGameURLs(self): 
    self.button = [] 
    for i in range(3): 
     self.button.append(Button(self, text='Game '+str(i+1),command=lambda:self.open_this(i))) 
     self.button[i].grid(column=4, row=i+1, sticky=W) 
def open_this(self, myNum): 
    print(myNum) 

Có cách nào để nhận giá trị i hiện tại, theo mỗi lần lặp lại, để gắn với nút cụ thể đó không? Cảm ơn bạn trước.

+0

Một lời cảm ơn lớn đến cả hai bạn LukaD và BrenBarn, tôi đã chiến đấu với điều đó trong vài ngày nay tin hay không. Cả hai cách đều hoạt động hoàn hảo. Tôi đã đi với i = i sửa chữa cho bây giờ, nhưng tôi chắc chắn sẽ đọc lên trên functools. Tôi đánh giá cao cả hai câu trả lời. – Marcel

+0

Nếu giải pháp BrenBarns hoạt động cho bạn thì bạn nên đánh dấu nó là câu trả lời được chấp nhận của bạn. – lukad

+0

có thể trùng lặp của [đối số truyền qua trong lệnh nút python Tkinter] (http://stackoverflow.com/questions/6920302/passing-argument-in-python-tkinter-button-command) –

Trả lời

6

Đây là cách đóng cửa hoạt động trong python. Tôi từng gặp vấn đề này một lần. Bạn có thể sử dụng functools.partial cho việc này.

for i in range(3): 
    self.button.append(Button(self, text='Game '+str(i+1), command=partial(self.open_this, i))) 
34

Thay đổi lambda thành lambda i=i: self.open_this(i).

Điều này có thể trông kỳ diệu, nhưng đây là những gì đang xảy ra. Khi bạn sử dụng lambda đó để xác định hàm của bạn, hàm open_this không nhận được giá trị của biến i tại thời điểm bạn xác định hàm. Thay vào đó, nó làm cho một đóng cửa, đó là loại giống như một lưu ý cho chính nó nói rằng "Tôi nên tìm những gì giá trị của biến i là tại thời điểm mà tôi được gọi là". Tất nhiên, hàm được gọi sau khi vòng lặp kết thúc, vì vậy tại thời điểm đó tôi sẽ luôn bằng giá trị cuối cùng từ vòng lặp.

Sử dụng thủ thuật i=i làm cho chức năng của bạn lưu trữ giá trị hiện tại của i tại thời điểm lambda của bạn được xác định, thay vì chờ để tra cứu giá trị của tôi sau này.

+0

nếu chúng ta muốn chuyển hai đối số cho một chức năng như open_this? – Amen

+1

@Amen: Nó phụ thuộc vào những gì bạn muốn những đối số được. Nếu cả hai đều đến từ một số vòng lặp bên ngoài và bạn muốn "đóng băng" chúng theo cách được hiển thị ở trên, bạn sẽ chỉ làm 'lambda x = x, y = y: self.open_this (x, y)'. – BrenBarn

+0

Đây là lời giải thích tuyệt vời, đơn giản và tốt. Đây sẽ là câu trả lời. – Battleroid