Search code examples
pythonpyqtpyqt5qtablewidgetqcombobox

Display the text of a checkable combobox to a QTableWidget


My code has a combobox with checkboxes and everytime I check a checkbox I want to display the text in a QTableWidget row and if a checkbox is unchecked I want to delete the row from the QTableWidget.


Solution

  • Although initially managing the logic with a QTableWidget with a QCombobox seems simple in the long term it could be complicated. A more elegant solution is to use a model that will be shared by the QComboBox and QTableView where the filtering is done by a QSortFilterProxyModel, when sharing both elements the same model will see the checkbox in the QTableWidget which is removed with a delegate.

    from PyQt5 import QtCore, QtGui, QtWidgets
    
    
    class CheckedFilterProxyModel(QtCore.QSortFilterProxyModel):
        def filterAcceptsRow(self, source_row, source_parent):
            index = self.sourceModel().index(source_row, 0, source_parent)
            return index.data(QtCore.Qt.CheckStateRole) == QtCore.Qt.Checked
    
    
    class RemoveCheckBoxDelegate(QtWidgets.QStyledItemDelegate):
        def initStyleOption(self, option, index):
            super(RemoveCheckBoxDelegate, self).initStyleOption(option, index)
            option.features &= ~QtWidgets.QStyleOptionViewItem.HasCheckIndicator
    
    
    class Widget(QtWidgets.QWidget):
        def __init__(self, parent=None):
            super(Widget, self).__init__(parent)
    
            self.m_combobox = QtWidgets.QComboBox()
            self.m_tableview = QtWidgets.QTableView()
    
            self.m_model = QtGui.QStandardItemModel(0, 2)
            self.m_proxy = CheckedFilterProxyModel(self)
            self.m_proxy.setSourceModel(self.m_model)
    
            self.m_combobox.setModel(self.m_model)
            self.m_tableview.setModel(self.m_proxy)
    
            delegate = RemoveCheckBoxDelegate(self)
            self.m_tableview.setItemDelegateForColumn(0, delegate)
    
            lay = QtWidgets.QVBoxLayout(self)
            lay.addWidget(self.m_combobox)
            lay.addWidget(self.m_tableview)
    
            options = ["Test1", "Test2", "Test3"]
    
            self.fill_combobox(options)
    
        def fill_combobox(self, options):
            self.m_model.clear()
            for option in options:
                item = QtGui.QStandardItem(option)
                item.setFlags(QtCore.Qt.ItemIsUserCheckable | QtCore.Qt.ItemIsEnabled)
                item.setData(QtCore.Qt.Unchecked, QtCore.Qt.CheckStateRole)
                items = [item] + [
                    QtGui.QStandardItem() for _ in range(self.m_model.rowCount() - 1)
                ]
                self.m_model.appendRow(items)
    
    
    if __name__ == "__main__":
        import sys
    
        app = QtWidgets.QApplication(sys.argv)
    
        w = Widget()
        w.show()
    
        sys.exit(app.exec_())