pythonpyside2qsignalmapper

Using QSignalMapper


I tried to make a simple example to help understand how the concept of QSignalMapping works in PySide. I would like to dynamically create a series of buttons by iterating through a loop, and when the user pushes one of the buttons, I can activate a method that returns the appropriate label for the button that was pressed.

from PySide2 import QtWidgets,QtCore,QtGui

fruit_list = ["apples","oranges","pears"]

def fruit_button_event():
    print "this is the pressed button's label"

def main():
    for fruit in fruit_list:
        fruit_button = QtWidgets.QPushButton(fruit)
        fruit_button.clicked.connect(lambda:fruit_button_event())
main()

Solution

  • In the next part I show an example how to use QSignalMapper:

    from PySide2 import QtCore, QtWidgets
    
    
    class Widget(QtWidgets.QWidget):
        def __init__(self, parent=None):
            super(Widget, self).__init__(parent)
            lay = QtWidgets.QVBoxLayout(self)
    
            fruit_list = ["apples","oranges","pears"]
            mapper =  QtCore.QSignalMapper(self)
            mapper.mapped[str].connect(self.fruit_button_event)
    
            for fruit in fruit_list:
                btn = QtWidgets.QPushButton(fruit)
                btn.clicked.connect(mapper.map)
                mapper.setMapping(btn, fruit)
                lay.addWidget(btn)
    
        @QtCore.Slot(str)
        def fruit_button_event(self, text):
            print("this is the pressed button's label", text)
    
    
    if __name__ == '__main__':
        import sys
    
        app = QtWidgets.QApplication(sys.argv)
        w = Widget()
        w.show()
        sys.exit(app.exec_())
    

    Remember that from Qt 5.10 QSignalMapper is deprecated:

    This class is obsolete. It is provided to keep old source code working. We strongly advise against using it in new code.


    The same functionality in python can be obtained with functools.partial(...):

    from PySide2 import QtCore, QtWidgets
    from functools import partial
    
    
    class Widget(QtWidgets.QWidget):
        def __init__(self, parent=None):
            super(Widget, self).__init__(parent)
            lay = QtWidgets.QVBoxLayout(self)
    
            fruit_list = ["apples","oranges","pears"]
    
            for fruit in fruit_list:
                btn = QtWidgets.QPushButton(fruit)
                btn.clicked.connect(partial(self.fruit_button_event, fruit))
                lay.addWidget(btn)
    
        @QtCore.Slot(str)
        def fruit_button_event(self, text):
            print("this is the pressed button's label", text)
    

    Or with lambda:

    btn.clicked.connect(lambda text=fruit: self.fruit_button_event(text))
    

    Or QButtonGroup:

    class Widget(QtWidgets.QWidget):
        def __init__(self, parent=None):
            super(Widget, self).__init__(parent)
            lay = QtWidgets.QVBoxLayout(self)
    
            fruit_list = ["apples","oranges","pears"]
            group = QtWidgets.QButtonGroup(self)
            group.buttonClicked.connect(self.OnButtonClicked)
    
            for fruit in fruit_list:
                btn = QtWidgets.QPushButton(fruit)
                group.addButton(btn)
                lay.addWidget(btn)
    
        @QtCore.Slot(QtWidgets.QAbstractButton)
        def OnButtonClicked(self, btn):
            print("this is the pressed button's label", btn.text())