0

I am new to pyqt (pyside in maya), please be nice to me :)

so the point is i want to generate many button via loop statement, something simmilar like below :

(5 button in a window - complete code - maya)

import PySide.QtCore as qc
import PySide.QtGui as qg
class simpleUI(qg.QDialog):
    def __init__(self):
        qg.QDialog.__init__(self)
        self.setWindowTitle('Simple UI')
        self.btn=[]
        for x in range(5) :
           self.btn.append(x)
           self.btn[x]= qg.QPushButton(self)
           self.btn[x].setText('this is btn number{0}'.format(x))
           self.btn[x].setGeometry(qc.QRect(0,100+(x*20), 100,20))
           self.btn[x].clicked.connect(lambda : self.notifyMe(x))
    def notifyMe(self,index):
        print index
dialog = simpleUI()
dialog.show()

as you see, I store button object in array, but the problem is when i want to connect btn signal with notifyMe function, every button always give x same value (x=4) , meanwhile in button.setText x succeed give unique incremental value, i can't figure it why..

Edit:

revisit this again after 6 years later, I wanna inform that I was always using partial rather than lambda, here is what I did on PySide2 / PyQt5:

import sys
from PySide2.QtWidgets import *
from functools import partial

class simpleUI:
    def __init__(self):
        app = QApplication()
        window = QMainWindow()
        layout = QVBoxLayout()

        for x in range(5):
            btn = QPushButton('this is btn number {0}'.format(x))
            btn.clicked.connect(partial(self.notifyMe, index=x))
            layout.addWidget(btn)
        widget = QWidget()
        widget.setLayout(layout)
        window.setCentralWidget(widget)
        #
        window.show()
        sys.exit(app.exec_())

    def notifyMe(self, index):
        print(index)

if __name__ == '__main__':
    simpleUI()

1 Answers1

6

It is old problem with function in lambda - it doesn't get value from x when you declare function but when you click button. But when you click button then for-loop is over and x keeps last value - and this way all buttons use the same value. You have to use

lambda a=x: self.notifyMe(a)
furas
  • 134,197
  • 12
  • 106
  • 148
  • thanks furas, you explained perfectly ! – Rifqi Khairur Rahman Nov 20 '16 at 14:45
  • 1
    I had to change it to also include the `checked` argument, that `clicked()` passes. eg. `lambda checked, a=x: self.notifyMe(a)`, as per comment in question https://stackoverflow.com/questions/51522883/pyqt5-signal-slot-not-connecting-correctly-when-creating-widgets-in-a-loop – Swedgin Nov 09 '20 at 11:01
  • @Swedgin it is very old question and code uses `PySide` which (as I remeber) was using `PyQt4` and it could work differently than in `PyQt5` – furas Nov 09 '20 at 15:52
  • I only mention it for future visitors. I'm using PyQt5 atm. – Swedgin Nov 10 '20 at 08:41
  • @Swedgin page not found, i'm looking for solution for pyqt5 – Sadique Khan Aug 28 '22 at 07:07
  • @SadiqueKhan question in link was deleted but when you will have more points of reputation then you may see it. – furas Aug 28 '22 at 09:03
  • @SadiqueKhan It was 4 years old question and it was closed as duplicate for questions [Python lambda doesn't remember argument in for loop](https://stackoverflow.com/questions/11723217/python-lambda-doesnt-remember-argument-in-for-loop), [Generating functions inside loop with lambda expression in python](https://stackoverflow.com/questions/1841268/generating-functions-inside-loop-with-lambda-expression-in-python), [Using lambda expression to connect slots in pyqt](https://stackoverflow.com/questions/35819538/using-lambda-expression-to-connect-slots-in-pyqt) – furas Aug 28 '22 at 09:07