class CheckableItemsModel(QStandardItemModel): checkStateChanged = pyqtSignal() def __init__(self, parent=None): super(CheckableItemsModel, self).__init__(parent) def flags(self, index): return super(CheckableItemsModel, self).flags(index) | Qt.ItemIsUserCheckable def data(self, index, role=Qt.DisplayRole): value = super(CheckableItemsModel, self).data(index, role) if index.isValid() and role == Qt.CheckStateRole and value is None: value = Qt.Unchecked return value def setData(self, index, value, role=Qt.EditRole): ok = super(CheckableItemsModel, self).setData(index, value, role) if ok and role == Qt.CheckStateRole: self.checkStateChanged.emit() return ok class CheckComboBox(QComboBox): checkedItemsChanged = pyqtSignal(list) def __init__(self, parent=None): super(CheckComboBox, self).__init__(parent) # workaround for Mac and GTK to show checkboxes self.setStyleSheet('QComboBox { combobox-popup: 1px }') self.defaultText = '' self.separator = ',' self.containerPressed = False self.checkableModel = CheckableItemsModel(self) self.setModel(self.checkableModel) self.model().checkStateChanged.connect(self.updateCheckedItems) self.model().rowsInserted.connect(self.updateCheckedItems) self.model().rowsRemoved.connect(self.updateCheckedItems) self.activated.connect(self.toggleCheckState) def itemCheckState(self, index): return self.itemData(index, Qt.CheckStateRole) def setItemCheckState(self, index, state): self.setItemData(index, state, Qt.CheckStateRole) def checkedItems(self): items = list() if self.model(): index = self.model().index(0, self.modelColumn(), self.rootModelIndex()) indexes = self.model().match(index, Qt.CheckStateRole, Qt.Checked, -1, Qt.MatchExactly) for i in indexes: items.append(index.data()) return items def setCheckedItems(self, items): for i in items: index = self.findText(i) self.setItemCheckState(index, Qt.Checked if index != -1 else Qt.Unchecked) def updateCheckedItems(self): items = self.checkedItems() if len(items) == 0: self.setEditText(self.defaultText) else: self.setEditText(self.separator.join(items)) self.checkedItemsChanged.emit(items) def toggleCheckState(self, index): value = self.itemData(index, Qt.CheckStateRole) if value is not None: self.setItemData(index, Qt.Checked if value == Qt.Unchecked else Qt.Unchecked, Qt.CheckStateRole)
В таком combobox'е элементы можно активировать и деактивировать. Но есть две проблемы, которые пока не могу решить:
- не работает множественный выбор. Т.е. можно выбрать только один элемент, и сразу после этого выпадающий список закрывается
- под Mac и GTK почему-то не отображаются чекбоксы, при этом в WIndows и KDE все отлично. Это не так критично, скорее всего, можно как-то решить при помощи стилей.
Буду признателен за помощь