Reputation: 995
My problem with the following code is passing 'i' (just a simple range of numbers but changes according to number_boxes) through lambda to callback in order to have seperate functionality of each box created.
I have tried reading tutorials and attempted various things in my code but it either doesn't work or I get errors 'lambda() requires only 2 arguments, 3 given' etc. I believe I would need to make 'i' a list but I still get this particular error..
I have commented on the code where the problems arise. I need to return the values inside each box as well as overwrite the text.
Thank you.
self.clicked = [] # In my __init__ definition
self.numbers = [StringVar() for i in xrange(self.number_boxes) ] # Create Stringvar for each box
for i in xrange(self.number_boxes): # For each number, create a box
self.clicked.append(False) # Not clicked in yet
self.box.append(Entry(self.frame_table,bg='white',borderwidth=0, width=10, justify="center", textvariable=self.numbers[i], fg='grey')) # Textvariable where I enter a value to get after, need to do for each box (use box[i] but cannot for append)
self.box[i].grid(row=row_list,column=column+i, sticky='nsew', padx=1, pady=1)
self.box[i].insert(0, "Value %g" % float(i+1))
self.box[i].bind("<Button-1>", lambda event, index=i : self.callback(event, index)) # Need to pass the 'i's' to callback but having lambda difficulties
for i in self.numbers:
i.trace('w',lambda index=i: self.numberwritten(index) ) # Need for each box again here
def numberwritten(self, index): # A way of combining numberwritten and callback?
po = self.box[index].get() # Get the values in each box
print po
def callback(self, event, index):
if (self.clicked[index] == False): # When clicked in box, overwrite default text with value and change colour to black, not grey
self.box[index].delete(0, END)
self.box[index].config(fg='black')
self.clicked[index] = True
UPDATE: Current problem: Need to pass all values of 'i' to callback and not just one but how to put list into lambda?
Error:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Python26\lib\lib-tk\Tkinter.py", line 1410, in __call__
return self.func(*args)
TypeError: lambda() takes at most 1 argument (3 given)
Upvotes: 2
Views: 3310
Reputation: 4255
Your code is very close, however this line:
self.box[i].bind("<Button-1>", lambda self, event,i : self.callback(event, data))
should be
self.box[i].bind("<Button-1>", lambda event, index=i: self.callback(event, index))
The object index
is just an arbitrary label to which we assign the value of i
. Note that Python throws an error if we pass i
, rather than a variable name. And we don't need to pass self
; it is passed implicitly by its use in the function call: self.callback()
.
My only other comment is that you should turn clicked
into a list, so that you can keep track of which objects the user selects. You can form this exactly the way box
is formed. Good luck.
Here are some tips on turning clicked
into a list, since I think this is current issue you are having. Edit: Changed several lines per J.F. Sebastian's comments.
# Create an empty list based on the number of boxes created
# above. This could go in your class's __init__ function,
# or it could be declared globally, depending on the scope
# of self.box and the loop which determines its length.
self.clicked = ([False] * len(self.box))
# Finally, in your callback, check one member of the list,
# depending on which box was clicked.
def cb(self, event, index):
if not self.clicked[index]:
self.box[index].delete(0, END)
self.box[index].config(fg='black')
self.clicked[index] = True
# Print the value of each of the widgets stored in the box list.
for i, j in enumerate(self.box):
print("%ith element: %s" % (i, j.get()))
Upvotes: 2
Reputation: 11614
updated: it seems your lambda is completly superflous. Remove it altogether.
try:
self.box[i].bind("<Button-1>",self.callback)
instead of:
lambda self, event, i: self.callback(event, i)
update:
While i was typing my answer you seemd to have worsened the situation, maybe a little clarification of the lambda-idiom would help you more then my solution above. ;-)
lambda-functions are also known as anonymous-function, for they don't need to have a name.
compare the following examples:
>>>ulist = 'a1 s3 d2 f4 k6 w9'.split()
def normal_sort(L,R):
result = int(L[1]) - int(R[1])
return result
>>> sorted(ulist, normal_sort)
['a1', 'd2', 's3', 'f4', 'k6', 'w9']
the same as a lambda-function:
sorted(ulist, lambda L, R: int(L[1])-int(R[1]))
['a1', 'd2', 's3', 'f4', 'k6', 'w9']
The lambda-function has
You may name a lambda-function by assigning it to a name:
lambda_sort = lambda L, R: int(L[1])-int(R[1])
but then it may be already useful to switch to a normal function.
Upvotes: 0