0

I am trying to create a sub-form to read files within a program. I have multiple buttons which basically repeat the same process on different files.

A button click calls the function "loadfiles" . The parameters passed, using a lambda function, to "loadfiles" are a string and a label.

    self.btnPts.clicked.connect(lambda: self.loadfiles("PtsFile",self.label))
    self.btnIll.clicked.connect(lambda: self.loadfiles("IllFile",self.label_2))
    self.btnSigIll.clicked.connect(lambda: self.loadfiles("SigIll",self.label_3))
    self.btn.clicked.connect(lambda: self.loadfiles("FutureFile",self.label_4)

Is there a way that I can group all the buttons together and compress these statements into one statement (something similar to Events in Excel VBA).

Can I add the buttons to a list and then bind the "clicked.connect" to it so that it calls my function evertime.

(I started coding in Python only 2 weeks back and this is my first time here. So please let me know if the details provided in the question are sufficient.)

Update . .

I was able to make this work by using partial functions. As I mentioned in my question above, I wanted to pass a particular string and a related label to a function when a button was clicked. And I wanted to do this in less verbose fashion.

I used a dictionary to store my buttons and used labels as keys. Then I used a for loop for iterating through the dictionary.

buttons = {self.btnPts:self.label,self.btnIll:self.label_2,self.btnSigIll:self.label_3,self.btn:self.label_4}

    for  button in  buttons:
       button.clicked.connect(partial(self.loadfiles,button.objectName(),buttons[button]))

Credit: I was able to work my way through this answer.. Connecting slots and signals in PyQt4 in a loop

Community
  • 1
  • 1

1 Answers1

0

If you want to do this simply, you need to create some sort of mapping between labels, buttons and the string you send to self.loadfiles.

For instance, a quick and dirty mapping by hand is:

mapping = [(self.btnPts, "PtsFile", self.label),
           (self.btnIll, "IllFile", self.label_2),
           (self.btnSigIll, "SigIll", self.label_3),
           (self.btn, "FutureFile", self.label_4)]

You can work out how to programmatically generate this mapping yourself (not enough information in your question for me to suggest how). There may be other formats that are also suitable.

You can then loop over this list and call clicked.connect as follows:

for button, filename, label in mapping:
    button.clicked.connect(lambda filename=filename, label=label: self.loadfiles(filename,label))

Note: it is very important that you keep the filename=filename, label=label part of the lambda definition. If you don't, when the lambda function executes, it will use the current contents of filename and label, which by the time the lambda function is executed (on button click) will always contain the data for the last iteration of the loop. Thus, the code would do the same thing whichever button you clicked.

three_pineapples
  • 11,579
  • 5
  • 38
  • 75
  • Oh...just saw you worked it out while I was writing my answer...oh well :) – three_pineapples Jul 30 '14 at 02:12
  • Brilliant! I was trying to make it work using lambda functions but gave up after trying for nearly an hour (for the same reason that you mentioned in the notes). Thanks a lot for explaining the lambda'esque way of doing this ! – Sarith Subramaniam Jul 30 '14 at 02:36