How to check filtered item in checkable ComboBox?

90 Views Asked by At

If an item in the list is selected using a filter, it becomes non-checkable. For filter I use functions: on_completer_activated, setModel, setModelColumn. I added a filter model to filter matching items (QSortFilterProxyModel), added a completer, which uses the filter model (QCompleter). On selection of an item from the completer, select the corresponding item from combobox (function "on_completer_activated"); on model change, update the models of the filter and completer as well (function "setModel"); on model column change, update the model column of the filter and completer as well (function "setModelColumn") How to make it checkable?

class CheckableComboBox(QComboBox):
    def __init__(self):
        super().__init__()
        self._changed = False
        self.view().pressed.connect(self.handleItemPressed)
        self.setFocusPolicy(Qt.StrongFocus)
        self.setEditable(True)
        self.pFilterModel = QSortFilterProxyModel(self)
        self.pFilterModel.setSourceModel(self.model())
        self.completer = QCompleter(self.pFilterModel, self)
        self.completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion)
        self.setCompleter(self.completer)
        self.lineEdit().textEdited.connect(self.pFilterModel.setFilterFixedString)
        self.completer.activated.connect(self.on_completer_activated)
    
    def setItemChecked(self, index, checked=False):
        item = self.model().item(index, self.modelColumn()) # QStandardItem object
        if checked:
            item.setCheckState(Qt.Checked)
        else:
            item.setCheckState(Qt.Unchecked)

    def handleItemPressed(self, index):
        item = self.model().itemFromIndex(index)

        if item.checkState() == Qt.Checked:
            item.setCheckState(Qt.Unchecked)
        else:
            item.setCheckState(Qt.Checked)
        self._changed = True
   
    def hidePopup(self):
        if not self._changed:
           super().hidePopup()
        self._changed = False

    def itemChecked(self, index):
        item = self.model().item(index, self.modelColumn())
        return item.checkState() == Qt.Checked

    def on_completer_activated(self, text):
        if text:
            index = self.findText(text)
            self.setCurrentIndex(index)
            self.activated[str].emit(self.itemText(index))
        
    def setModel(self, model):
        super(CheckableComboBox, self).setModel(model)
        self.pFilterModel.setSourceModel(model)
        self.completer.setModel(self.pFilterModel)

    def setModelColumn(self, column):
        self.completer.setCompletionColumn(column)
        self.pFilterModel.setFilterKeyColumn(column)
        super(CheckableComboBox, self).setModelColumn(column)    

class MyApp(QWidget):
    def __init__(self):
        super().__init__()
        self.resize(500, 150)
        mainLayout = QVBoxLayout()
        self.combo = CheckableComboBox()
        mainLayout.addWidget(self.combo)

        for i in range(7):
            self.combo.addItem('Item {0}'.format(str(i)))
            self.combo.setItemChecked(i, False)     
            self.setLayout(mainLayout)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    app.setStyleSheet('QWidget {font-size: 40px;}')

    myApp = MyApp()
    myApp.show()
    app.exit(app.exec_())`          

enter image description here

I'm trying to make a filtered item checkable.

0

There are 0 best solutions below