Найти - Пользователи
Полная версия: QComboBox с множественным выбором
Начало » GUI » QComboBox с множественным выбором
1 2
_alexs_
Потребовалась возможность множественного выбора элементов в 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)

В таком combobox'е элементы можно активировать и деактивировать. Но есть две проблемы, которые пока не могу решить:
  1. не работает множественный выбор. Т.е. можно выбрать только один элемент, и сразу после этого выпадающий список закрывается
  2. под Mac и GTK почему-то не отображаются чекбоксы, при этом в WIndows и KDE все отлично. Это не так критично, скорее всего, можно как-то решить при помощи стилей.

Буду признателен за помощь
PEHDOM
жесть какая… зачем придумывать велосипед?
http://stackoverflow.com/a/22775990
и допиливайте как вам нравится
_alexs_
PEHDOM
жесть какая… зачем придумывать велосипед?
Почему «жесть»? Использование моделей это нормальный подход. ИМХО, устанавливать ручками каждому элементу флажок, пробегаясь по ним в цикле, менее удобно, особенно, если содержимое меняется динамически.

Ваш пример страдает той же проблемой, что и мой код: при выборе одного элемента выпадающий список закрывается. Т.е. нельзя выбрать все необходимые элементы сразу.
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_())

Rodegast
Жесть не в модели, а в самой задачи. Для множественного выбора ComboBox по определению не предназначен.
anton666
А подскажите пожалуйста, как кроме использования ComboBox, реализовать список со множественным выбором?
PEHDOM
anton666
А подскажите пожалуйста, как кроме использования ComboBox, реализовать список со множественным выбором?
да как угодно, комбобокс это скорее от боезысхожности. А вообще для этого придумали специально чекбоксы.
anton666
В смысле специальные? Мне необходимо реализовать некий список, в котором можно выбрать сразу несколько значений.
Как это чекбоксами реализовать? Создать отдельное окно на котором будут располагаться подписанные чекбоксы?
PEHDOM
anton666
Как это чекбоксами реализовать? Создать отдельное окно на котором будут располагаться подписанные чекбоксы?
тут все зависит от ваших задач\дизайна, есть еще QListWidget, собственно тоже для этого придуман, есть чекбоксы которые можно обьединить в фрейме/виджете, даже можно извратиться и QTableWidget для этого использовать.
KriO
PEHDOM
На мой взгляд, QTableWidget - самый подходящий простой вариант для такой задачи.
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB