2

I am trying to populate the screen with multiple buttons automatically (using for loop)

Here is the snippet:

    i = 0
    for w in [1,2,3,4,5,6,7,8]:
        by.append(wx.Button(panel,label=w,pos = wx.Point(50*i,0)))
        by[i].Bind(wx.EVT_LEFT_DOWN,lambda event: self.OnClicked(event,by[i]))
        i += 1
    i = 0

when the event occurs, since I set the i = 0, all of the events are routed to the first button, even if I click on the last button. I know that if I set the slot with out the for loop it would work. But lets say I need to create about 50 buttons on a screen, and I want to do it automatically. How would I set the slot?

Santosh Kumar
  • 26,475
  • 20
  • 67
  • 118
Wobblester
  • 748
  • 4
  • 8
  • 18

1 Answers1

2

The problem is the lambda expression lambda event: self.OnClicked(event,by[i])). You can read more on the basic problem here: What do (lambda) function closures capture?.

But in short: The i is not fixed at the creation of the lambda expression. After the loop has ended, all the lambda expressions still refer to i. That means all of them have the same value.

A dirty fix would be to use this instead:

by[i].Bind(wx.EVT_LEFT_DOWN,lambda event, i=i: self.OnClicked(event,by[i]))

But it might be better to use another helper function to do the variable binding:

def addOnClicked(i,w):
    by.append(wx.Button(panel,label=w,pos = wx.Point(50*i,0)))
    by[i].Bind(wx.EVT_LEFT_DOWN,lambda event: self.OnClicked(event,by[i]))

for i in range(8):
    addOnClicked(i,i+1)
Community
  • 1
  • 1
Michael Mauderer
  • 3,777
  • 1
  • 22
  • 49