0

I have a similar problem to Using lambda expression to connect slots in pyqt. In my case, I want to send two different pieces of information. Which button is being clicked (the port number) and the sensor associated with that port number (stored in a QComboBox).

This is what I want to achieve and this works fine:

self.portNumbers[0].clicked.connect(lambda: self.plot(1, self.sensorNames[0].currentText()))
self.portNumbers[1].clicked.connect(lambda: self.plot(2, self.sensorNames[1].currentText()))
self.portNumbers[2].clicked.connect(lambda: self.plot(3, self.sensorNames[2].currentText()))
...

But when I put this in a loop as this:

for i, (portNumber, sensorName) in enumerate(zip(self.portNumbers, self.sensorNames)):
    portNumber.clicked.connect(lambda _, x=i + 1, y=sensorName.currentText(): self.plot(x, y))

I get the correct port numbers but the change in the Combo box is not reflected.

Minimum reproducible code:

from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QComboBox

portNumbers = [None] * 8
sensorNames = [None] * 8
SENSORS = ["Temperature", "Pressure", "Height"]


class MyWidget(QWidget):
    def __init__(self):
        super().__init__()

        self.init_ui()
        self.connectButtonsToGraph()

    def init_ui(self):
        vbox = QVBoxLayout()
        h1box = QHBoxLayout()
        h2box = QHBoxLayout()
        for i, (portNumber, sensorName) in enumerate(zip(portNumbers, sensorNames)):
            # Set portNumber as pushButton and list sensorNames in ComboBox
            portNumber = QPushButton()
            sensorName = QComboBox()
            h1box.addWidget(portNumber)
            h2box.addWidget(sensorName)

            # Give identifier, text info to individual ports and modify the list
            portNumberName = "port_" + str(i + 1)
            portNumber.setObjectName(portNumberName)
            portNumberText = "Port " + str(i + 1)
            portNumber.setText(portNumberText)
            portNumbers[i] = portNumber

            # Add the textual information in PushButton and add modify the list
            sensorNameStringName = "portSensorName_" + str(i + 1)
            sensorName.setObjectName(sensorNameStringName)
            for counter, s in enumerate(SENSORS):
                sensorName.addItem("")
                sensorName.setItemText(counter, s)
            sensorNames[i] = sensorName

        vbox.addLayout(h1box)
        vbox.addLayout(h2box)
        self.setLayout(vbox)

        self.show()

    def connectButtonsToGraph(self):
        for i, (portNumber, sensorName) in enumerate(zip(portNumbers, sensorNames)):
            portNumber.clicked.connect(lambda _, x=i + 1, y=sensorName.currentText(): self.plot(x, y))

    def plot(self, portNumber, sensorName):
        print(portNumber, sensorName)


def run():
    app = QApplication([])
    mw = MyWidget()
    app.exec_()


if __name__ == '__main__':
    run()

linkingashu
  • 123
  • 1
  • 1
  • 7
  • 1
    The problem is the same: the value of the keyword argument of lambda is evaluated when it's created. Change to `lambda _, x=i + 1, combo=sensorName: self.plot(x, combo.currentText())` – musicamante Mar 30 '22 at 22:47

1 Answers1

0

Thank you, @musicamante, for the explanation. I am just adding it in the answer to mark it as solved if someone has similar issues.

As they mentioned, the value of the keyword argument of lambda is evaluated when it's created. So, creating a reference to sensorName.currentText() used the value of the current text at that time. But creating a reference to the ComboBox itself allowed for getting the value of the text in run-time.

linkingashu
  • 123
  • 1
  • 1
  • 7