PyQt - How to set QComboBox in a table view using QItemDelegate

后端 未结 1 1415
清歌不尽
清歌不尽 2020-12-01 08:50

I am trying to display a combo box in my table, so that I can set the selected index from the table model, as with the other cells in the table. I have pieced this together

相关标签:
1条回答
  • 2020-12-01 09:32

    You're using paint method incorrectly. It should be used when you want to change displaying behavior of the view. Also creating new widget each time you want to paint it is very expensive. But you want to change editing behavior so you need to change entire logic of your program.

    See the fixed code. Below I'll expain the changes.

    1. First of all, we need to make the first column editable. You can do it by reimplementing QAbstractItemModel::flags:

    def flags(self, index):
        if (index.column() == 0):
            return QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsEnabled
        else:
            return QtCore.Qt.ItemIsEnabled
    

    2. By default the item editor is created when user performs a double click on item. If you want to show all comboboxes by default, you can use openPersistentEditor:

    for row in range(0, self._tm.rowCount()):
        self._tv.openPersistentEditor(self._tm.index(row, 0))
    

    Note that you should also open editors for newly created cells (if any).

    3. Now back to our delegate. We need to implement createEditor method that will be automatically called by the view when an editor is requested for a cell:

    def createEditor(self, parent, option, index):
        combo = QtGui.QComboBox(parent)
        li = []
        li.append("Zero")
        li.append("One")
        li.append("Two")
        li.append("Three")
        li.append("Four")
        li.append("Five")
        combo.addItems(li)
        self.connect(combo, QtCore.SIGNAL("currentIndexChanged(int)"), 
                     self, QtCore.SLOT("currentIndexChanged()"))
        return combo
    

    Note that connect is below appends because we need to avoid currentIndexChanged signals on initialization.

    4. Implement setEditorData method that will be called by the view when model data has been changed. Also it will be called once when an editor is initialized.

    def setEditorData(self, editor, index):
        editor.blockSignals(True)
        editor.setCurrentIndex(int(index.model().data(index)))
        editor.blockSignals(False)
    

    Again, we want to avoid signals that are not caused by the user, so we use blockSignals.

    5. In the slot we simply emit commitData signal that will cause the view to call the setModelData of our delegate:

    @QtCore.pyqtSlot()
    def currentIndexChanged(self):
        self.commitData.emit(self.sender())
    

    6. Implement setModelData method:

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

    7. Your model needs to support data changing. So we should implement setData method of the model:

    def setData(self, index, value, role=QtCore.Qt.DisplayRole):
        print "setData", index.row(), index.column(), value
        # todo: remember the data
    
    0 讨论(0)
提交回复
热议问题