2

I have several buttons, each with a Signal that emits one of their attributes (say, an integer) whenever the button is clicked. In a parent class, I'd like to be able to catch any of the buttons' emits and react based on that particular attribute from the button.

I can think of a way to do that by individually 'connecting' each button in the parent class, but that seems wrong, and cumbersome, because in my application I add and remove buttons as part of the functionality. I'm probably thinking about it wrongly... and suggestions?

NoDataDumpNoContribution
  • 10,591
  • 9
  • 64
  • 104
Saar Drimer
  • 1,171
  • 2
  • 11
  • 24
  • 1
    [Qt signals and slots for multiple objects](http://stackoverflow.com/questions/15316032/qt-signals-and-slots-for-multiple-objects) or [Connecting multiple signals to a single slot in Qt](http://stackoverflow.com/questions/2169487/connecting-multiple-signals-to-a-single-slot-in-qt) or [multiple signals for one slot](http://stackoverflow.com/questions/11328788/multiple-signals-for-one-slot) might also help you. – NoDataDumpNoContribution Jun 20 '14 at 08:12

2 Answers2

4

You can do something like this:

from functools import partial

def buttonEvent(i):
    print(i)

for i in range(5):
    button = QtWidgets.QPushButton("Button: " + str(i))
    button.clicked.connect(partial(buttonEvent, i))

In Qt, you need to connect signals to function names, you cannot specify parameters or anything. This is annoying when it comes to many unique widgets or generated widgets or whatnot. Two decent solutions are to use partial and lambda. I use lambda when I want to call a function with parameters independent of a variable (e.g. button.clicked.connect(lambda: print("Button clicked"))). If your function call is dependent on some variable that will be changed later, you need to use partial, which will save the variable contents right away. Lambda will wait until being called to use the variable (so, in the above case, all buttons would print "4" if lambda was used).

user3525381
  • 227
  • 1
  • 4
3

In Qt you can connect any signal with any slot. This also means you can connect a single signal with several slots or several signals with a single slot.

Now if every button does a different thing and there aren't that many I would connect each one manually with a different slot just to have things nicely separated.

In your case you probably want to connect all the buttons with a single slot in an automatic fashion and in this slot determine the button of origin by self.sender() and then do something with this information.

Example:

Whenever a new button occurs in your widget

new_button.clicked.connect(self.parent().buttons_clicked)
# always the same recipient

And in the parent class:

def buttons_clicked(self):
  button = self.sender()
  # do something useful depending on the button that sent the signal

What is missing here is the way you transfer your attribute (the number or whatever). You didn't specify how you do it now but it should probably not be altered significantly by connecting to the same slot.


edit: As a sidenote, there are also events in Qt which roughly do the same. Signals/slots vs events is an interesting discussion. Depending on your problem (many dynamic buttons) instead of connecting and disconnecting you might be better off with sending events.

Community
  • 1
  • 1
NoDataDumpNoContribution
  • 10,591
  • 9
  • 64
  • 104
  • Thanks for that! I think that this also sorted things out in my head in terms of parent relationship arrangement ;) – Saar Drimer Jun 20 '14 at 10:09