Форум сайта python.su
Потребовалась возможность множественного выбора элементов в QComboBox. Для этого создал модель, которая автоматически устанавливает элементам флажок Qt.ItemIsUserCheckable и свой класс на основе QComboBox, где эта модель используется. Вот код
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)
Офлайн
жесть какая… зачем придумывать велосипед?
http://stackoverflow.com/a/22775990
и допиливайте как вам нравится
[code python][/code]
Отредактировано PEHDOM (Март 14, 2017 23:44:23)
Офлайн
PEHDOMПочему «жесть»? Использование моделей это нормальный подход. ИМХО, устанавливать ручками каждому элементу флажок, пробегаясь по ним в цикле, менее удобно, особенно, если содержимое меняется динамически.
жесть какая… зачем придумывать велосипед?
Офлайн
_alexs_жесть в самой модели, в моем примере много меньше букаф, хотя ХЗ может вам оно все надо.
Почему «жесть»? Использование моделей это нормальный подход.
_alexs_ну дык это вам надо переопределять hidePopup, а модель тут вообще нипричем.
Ваш пример страдает той же проблемой, что и мой код: при выборе одного элемента выпадающий список закрывается. Т.е. нельзя выбрать все необходимые элементы сразу.
from PyQt4 import QtGui, QtCore import sys, os class CheckableComboBox(QtGui.QComboBox): def __init__(self): super(CheckableComboBox, self).__init__() self.view().pressed.connect(self.handleItemPressed) self.setModel(QtGui.QStandardItemModel(self)) def hidePopup(self): #переопределяем hidePopup if not self.view().underMouse(): ##скрывать выпадающий список только если курсор не над списком QtGui.QComboBox.hidePopup(self) def handleItemPressed(self, index): item = self.model().itemFromIndex(index) if item.checkState() == QtCore.Qt.Checked: item.setCheckState(QtCore.Qt.Unchecked) else: item.setCheckState(QtCore.Qt.Checked) class Dialog_01(QtGui.QMainWindow): def __init__(self): super(QtGui.QMainWindow,self).__init__() myQWidget = QtGui.QWidget() myBoxLayout = QtGui.QVBoxLayout() myQWidget.setLayout(myBoxLayout) self.setCentralWidget(myQWidget) self.ComboBox = CheckableComboBox() for i in range(3): self.ComboBox.addItem("Combobox Item " + str(i)) item = self.ComboBox.model().item(i, 0) item.setCheckState(QtCore.Qt.Unchecked) myBoxLayout.addWidget(self.ComboBox) if __name__ == '__main__': app = QtGui.QApplication(sys.argv) dialog_1 = Dialog_01() dialog_1.show() dialog_1.resize(480,320) sys.exit(app.exec_())
[code python][/code]
Отредактировано PEHDOM (Март 15, 2017 15:42:09)
Офлайн
Жесть не в модели, а в самой задачи. Для множественного выбора ComboBox по определению не предназначен.
Офлайн
А подскажите пожалуйста, как кроме использования ComboBox, реализовать список со множественным выбором?
Офлайн
anton666да как угодно, комбобокс это скорее от боезысхожности. А вообще для этого придумали специально чекбоксы.
А подскажите пожалуйста, как кроме использования ComboBox, реализовать список со множественным выбором?
[code python][/code]
Отредактировано PEHDOM (Июль 19, 2018 09:15:31)
Офлайн
В смысле специальные? Мне необходимо реализовать некий список, в котором можно выбрать сразу несколько значений.
Как это чекбоксами реализовать? Создать отдельное окно на котором будут располагаться подписанные чекбоксы?
Офлайн
anton666тут все зависит от ваших задач\дизайна, есть еще QListWidget, собственно тоже для этого придуман, есть чекбоксы которые можно обьединить в фрейме/виджете, даже можно извратиться и QTableWidget для этого использовать.
Как это чекбоксами реализовать? Создать отдельное окно на котором будут располагаться подписанные чекбоксы?
[code python][/code]
Офлайн
PEHDOMНа мой взгляд, QTableWidget - самый подходящий простой вариант для такой задачи.
Офлайн