如何创建组合框QItemDelegate

时间:2016-12-18 10:34:48

标签: python qt pyside qcombobox qitemdelegate

我实现了以下委托,在QTableView中提供了一个组合框。用例是用对应的文本替换对用户通常没有意义的列(键)(例如数字id)。

下面的代码段有效(也用于保存正确的值),但它有三个问题:

  1. 显示原始值,而不是文本等效值。
  2. QTableView中的选择行提供所有列,但不提供具有此委托的列。
  3. 理想情况下,我希望组合框看起来像这样,用户不必点击它就能发现它是一个。
  4. 注意:键可以是任何字符串(不一定是整数)。 一个典型的例子是国家(值“法国”对应于键“FR”)。

    class ComboDelegate(QtGui.QItemDelegate):
        """
        A delegate that places a QComboBox in every
        cell of the column to which it is being applied
        """
    
        def __init__(self, parent, value_data):
            "Value_data is a list of tuples: (item, label)"
            QtGui.QItemDelegate.__init__(self, parent)
            self.value_data = value_data
    
        @property
        def items(self):
            "The list of items for display"
            return [item[0] for item in self.value_data]
    
        @property
        def labels(self):
            "The list of labels for display"
            return [item[1] for item in self.value_data]
    
        def item(self, label):
            "Get the item from a label"
            try:
                index = self.labels.index(label)
            except ValueError:
                pass
            print("Value no:  &%s" % index)
            return self.items[index]
    
        def createEditor(self, parent, option, index):
            "Create the editor (called each time)"
    
            combo = QtGui.QComboBox(parent)
            for duplet in self.value_data:
                # the duplet is label, item
                item, label = duplet
                combo.addItem(label)
    
            combo.currentIndexChanged.connect(self.currentIndexChanged)
            return combo
    
        def setEditorData(self, editor, index):
            editor.blockSignals(True)
            editor.setCurrentIndex(index.row())
            editor.blockSignals(False)
    
        def setModelData(self, editor, model, index):
            "This is the data stored into the field"
            print("Current text: %s" % editor.currentText())
            model.setData(index, self.item(editor.currentText()))
    
        def currentIndexChanged(self):
            self.commitData.emit(self.sender())
    

2 个答案:

答案 0 :(得分:2)

添加{your table view}.openPersistentEditor({your QModelIndex}) 这是我的解决方案:

import sys
from PySide import QtGui, QtCore


class ComboBoxDelegate(QtGui.QItemDelegate):
    def __init__(self, parent=None):
        super(ComboBoxDelegate, self).__init__(parent)
        self.items = []

    def setItems(self, items):
        self.items = items

    def createEditor(self, widget, option, index):
        editor = QtGui.QComboBox(widget)
        editor.addItems(self.items)
        return editor

    def setEditorData(self, editor, index):
        value = index.model().data(index, QtCore.Qt.EditRole)
        if value:
            editor.setCurrentIndex(int(value))

    def setModelData(self, editor, model, index):
        model.setData(index, editor.currentIndex(), QtCore.Qt.EditRole)

    def updateEditorGeometry(self, editor, option, index):
        editor.setGeometry(option.rect)

    def paint(self, painter, option, index):
        text = self.items[index.row()]
        option.text = text
        QtGui.QApplication.style().drawControl(QtGui.QStyle.CE_ItemViewItem, option, painter)

if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    column = 0
    model = QtGui.QStandardItemModel(4, 2)
    tableview = QtGui.QTableView()
    tableview.setModel(model)
    delegate = ComboBoxDelegate()
    delegate.setItems([str(x) for x in range(10)])
    tableview.setItemDelegateForColumn(column, delegate)

    for row in range(4):
        for col in range(2):
            index = model.index(row, col, QtCore.QModelIndex())
            value = (row + 1)*(col + 1)
            model.setData(index, value)

    for i in range(model.rowCount()):
        tableview.openPersistentEditor(model.index(i, column))
    tableview.show()
    sys.exit(app.exec_())

enter image description here

enter image description here

放置了字符串,因为我在上一个示例中使用的是str(),我向您展示了另一个显示国家/地区的示例。

import sys
from PySide import QtGui, QtCore


class ComboBoxDelegate(QtGui.QItemDelegate):
    def __init__(self, parent=None):
        super(ComboBoxDelegate, self).__init__(parent)
        self.items = []

    def setItems(self, items):
        self.items = items

    def createEditor(self, widget, option, index):
        editor = QtGui.QComboBox(widget)
        editor.addItems(self.items)
        return editor

    def setEditorData(self, editor, index):
        value = index.model().data(index, QtCore.Qt.EditRole)
        if value:
            editor.setCurrentIndex(int(value))

    def setModelData(self, editor, model, index):
        model.setData(index, editor.currentIndex(), QtCore.Qt.EditRole)

    def updateEditorGeometry(self, editor, option, index):
        editor.setGeometry(option.rect)

    def paint(self, painter, option, index):
        text = self.items[index.row()]
        option.text = text
        QtGui.QApplication.style().drawControl(QtGui.QStyle.CE_ItemViewItem, option, painter)

if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    column = 0
    model = QtGui.QStandardItemModel(4, 2)
    tableview = QtGui.QTableView()
    tableview.setModel(model)
    delegate = ComboBoxDelegate()
    delegate.setItems([QtCore.QLocale.countryToString(QtCore.QLocale.Country(locale)) for locale in range(QtCore.QLocale.Afghanistan, QtCore.QLocale.Zulu+ 1 )])
    tableview.setItemDelegateForColumn(column, delegate)

    for row in range(4):
        for col in range(2):
            index = model.index(row, col, QtCore.QModelIndex())
            value = (row + 1)*(col + 1)
            model.setData(index, value)

    for i in range(model.rowCount()):
        tableview.openPersistentEditor(model.index(i, column))
    tableview.show()
    sys.exit(app.exec_())

enter image description here enter image description here

答案 1 :(得分:1)

第一个问题最容易通过模型解决,即它可以在被要求DisplayRole时提供特定值的文本,并且仍然通过EditRole提供数值。

为了显示组合框,有两个选项

  1. 使用委托时,覆盖paint()方法以绘制组合框,例如通过委托当前的小部件样式,就像QComboBox本身一样

  2. 而不是委托,设置索引小部件。见QAbstractItemView::setIndexWidget()