Search code examples
pythonqtpyqtqtablewidgetqcheckbox

Get state of checkbox cellWidget in QTableWidget PyQT


I work on python plugin for QGIS. In this plugin I have created a QTableWidget with 3 columns. These columns are QCheckbox, QTableWidgetItem and QComboBox. I would like to retrieve the values contained in these 3 columns. For the moment I managed to get the values of QComboBox and QTableWidgetItem but I can't seem to get the value of the QCheckBox.

liste = ['Carte 1','Carte 2','Carte 3','Carte 4','Carte 5','Carte 6']
        combo_box_options = ["A4 Paysage","A4 Portrait", "A3 Paysage","A3 Portrait"]
        self.dlg_format = Dialog_format()
        self.dlg_format.tableWidget.setRowCount(len(liste))

        for index in range(len(liste)):
            item = QTableWidgetItem(liste[index])
            self.dlg_format.tableWidget.setItem(index, 1, item)
            self.dlg_format.tableWidget.setColumnWidth(0, 20)
            self.dlg_format.tableWidget.setColumnWidth(1, 350)

            combo = QComboBox()
            for t in combo_box_options:
                combo.addItem(t)
            self.dlg_format.tableWidget.setCellWidget(index, 2, combo)

            widget = QWidget()
            checkbox = QCheckBox()
            checkbox.setCheckState(Qt.Checked)
            playout = QHBoxLayout(widget)
            playout.addWidget(checkbox)
            playout.setAlignment(Qt.AlignCenter)
            playout.setContentsMargins(0,0,0,0)
            widget.setLayout(playout)
            self.dlg_format.tableWidget.setCellWidget(index, 0, widget)

        self.dlg_format.show()
        result = self.dlg_format.exec_()

        if result:
            for index in range(len(liste)):
                text = self.dlg_format.tableWidget.item(index, 1).text()
                format = self.dlg_format.tableWidget.cellWidget(index, 2).currentText()
                check = self.dlg_format.tableWidget.cellWidget(index, 0).checkState() #Does not work


Solution

  • The QWidget is what is set as cell widget, not the checkbox, and that widget obviously has no checkState attribute.

    There are various possibilities for this scenario.

    Make the checkbox an attribute of the widget:

        widget = QWidget()
        widget.checkbox = QCheckBox()
        playout.addWidget(widget.checkbox)
    
        # ...
        check = self.dlg_format.tableWidget.cellWidget(index, 0).checkbox.checkState()

    Make the checkbox's checkState function a reference of the widget (note: no parentheses!) so that you can access it with the existing cellWidget(index, 0).checkState():

        checkbox = QCheckBox()
        widget.checkState = checkbox.checkState
    

    Since all happens within the same scope (the function), you can totally ignore the cellWidget and use a list of tuples that contains the widgets:

        widgets = []
        for index in range(len(liste)):
            # ...
            widgets.append((item, combo, checkbox))
        # ...
        if result:
            for item, combo, checkbox in widgets:
                text = item.text()
                format = combo.currentText()
                check = checkbox.checkState()
    

    Note that:

    • checkState() returns a Qt.CheckState enum, which results in 2 (Qt.Checked) for a checked box; if you need a boolean, use isChecked() instead;
    • you can use enumerate instead of range, since you are iterating through the list items anyway: for index, text in enumerate(liste):;
    • if you don't need to add item data and the contents of the combo are always the same, just use combo.addItems(combo_box_options);
    • setting the column width for every cycle is pointless, just do it once outside the for loop;
    • if you use QHBoxLayout(widget) there's no need for widget.setLayout(playout), as the widget argument on a layout already sets that layout on the widget;
    • instance attribute are created in order to make them persistent (it ensures that they are not garbage collected and allows future access); from your code it seems unlikely that you're going to use that dialog instance after that function returns, so making it a member of the instance (self.dlg_format) is unrequired and keeps resources unnecessarily occupied: the dialog would be kept in memory even after it's closed, and would be then deleted and overwritten as soon as it's created again; just make it a local variable (dlg_format = Dialog_format());