mabdeltawab
mabdeltawab

Reputation: 25

PyQT signal connection with extra information using Lambda is not working correctly

I'm running a simple code to creat 4 checkboxes in a widget I have a simple function to change the checkbox text when clicked based on wheater it's checked or not

I'm trying to connect the "clicked" signal to slot "on_checkBox_ss" using Lambda method to pass an extar parameter to identify the clicked checkbox

but it's not working well, it pass False/True instead of the checkbox index

here is the code

from PyQt6 import QtWidgets
from PyQt6.QtWidgets import QWidget, QCheckBox, QApplication, QVBoxLayout

class mainwidget():
    def __init__(self) -> None:
        super().__init__()
        self.widget = QWidget()
        vlayout = QVBoxLayout(self.widget)
        self.CHK_BoxGRP = [checkBoxClass(self.widget,f"ChkBox_{x}") for x in range(0,4)]
        [vlayout.addWidget(self.CHK_BoxGRP[i].chkbox) for i in range(0,4)]
        
        # Build the connection
        [self.CHK_BoxGRP[y].chkbox.clicked.connect(lambda y:self.on_checkBox_ss(y)) for 
        y in range (0,4)]
  
    #function to process the clicked checkbox
    def on_checkBox_ss(self,boxnum):
        if self.CHK_BoxGRP[boxnum].chkbox.isChecked():
            self.CHK_BoxGRP[boxnum].chkbox.setText("Clicked")
        else:
            self.CHK_BoxGRP[boxnum].chkbox.setText("Not Clicked")

"""  Below is check box class """
class checkBoxClass:
    
    def __init__(self,PARENT,CHKLABEL) -> None:
        #super().__init__()
        self.parent = PARENT
        self.chkLabel = CHKLABEL
        #self.operat_on = OPERAT_ON
        
        self.chkbox = QtWidgets.QCheckBox(self.parent)
        self.chkbox.setStyleSheet("border-color: rgb(85, 85, 255);")
        self.chkbox.setObjectName(self.chkLabel)
        self.chkbox.setChecked(True)
        self.chkbox.setText(f"GROUP {self.chkLabel[-1]}")


""" start of main code"""        
if __name__ == "__main__":
    import sys
    
    app = QtWidgets.QApplication(sys.argv)
    mainwindow = mainwidget()
    
    mainwindow.widget.show()
    
    sys.exit(app.exec())

Upvotes: 0

Views: 187

Answers (1)

Atalay
Atalay

Reputation: 26

QPushButton.clicked.connect() method automatically passes the state of the button (bool) as default first argument, so if there is only one argument -which is 'y' in comprehension in this case- is overwritten with the state of the button.

You can see that if you just print(boxnum) in 'on_checkBox_ss', it prints out True or False which is the state of clicked button, and by coincidence list[True] will return #1 index and list[False] will return #0 (as it should be because boolean expressions are just 0 or 1 at the end of the day)

I said that this was a coincidence because your code actually works (just not the way as intended) and doesn't give an error which make it seem like the problem has something to do with signals and loops in the framework.

So the solution is to overwrite the state argument with anything (which will be 'x' -or anything for that matter) and pass 'y' explicitly.

[self.CHK_BoxGRP[y].chkbox.clicked.connect(lambda x="", y=y: self.on_checkBox_ss(y)) for y in range(4)]

So it will be:

from PyQt6 import QtWidgets
from PyQt6.QtWidgets import QWidget, QCheckBox, QApplication, QVBoxLayout

class mainwidget():
    def __init__(self) -> None:
        super().__init__()
        self.widget = QWidget()
        vlayout = QVBoxLayout(self.widget)
        self.CHK_BoxGRP = [checkBoxClass(self.widget,f"ChkBox_{x}") for x in range(0,4)]
        [vlayout.addWidget(self.CHK_BoxGRP[i].chkbox) for i in range(0,4)]
        
        # Build the connection
        #[self.CHK_BoxGRP[y].chkbox.clicked.connect(lambda y:self.on_checkBox_ss(y)) for 
        #y in range (0,4)]
        
        [self.CHK_BoxGRP[y].chkbox.clicked.connect(lambda x="", y=y:self.on_checkBox_ss(y)) for y in range(4)]

  
    #function to process the clicked checkbox
    def on_checkBox_ss(self,boxnum):
        print(boxnum) # now prints out actual y value instead of True or False
        if self.CHK_BoxGRP[boxnum].chkbox.isChecked():
            self.CHK_BoxGRP[boxnum].chkbox.setText("Clicked")
        else:
            self.CHK_BoxGRP[boxnum].chkbox.setText("Not Clicked")

"""  Below is check box class """
class checkBoxClass:
    
    def __init__(self,PARENT,CHKLABEL) -> None:
        #super().__init__()
        self.parent = PARENT
        self.chkLabel = CHKLABEL
        #self.operat_on = OPERAT_ON
        
        self.chkbox = QtWidgets.QCheckBox(self.parent)
        self.chkbox.setStyleSheet("border-color: rgb(85, 85, 255);")
        self.chkbox.setObjectName(self.chkLabel)
        self.chkbox.setChecked(True)
        self.chkbox.setText(f"GROUP {self.chkLabel[-1]}")


""" start of main code"""        
if __name__ == "__main__":
    import sys
    
    app = QtWidgets.QApplication(sys.argv)
    mainwindow = mainwidget()
    
    mainwindow.widget.show()
    
    sys.exit(app.exec())

Upvotes: 1

Related Questions