Search code examples
pythonpyqt4qabstracttablemodel

Edit table in PyQt QAbstractTableModel without deletion of content


What I have done so far:

I'm implementing an custom QAbstractTableModel (used in a QTableView-Widget) that contains editable cells. The properties of these cells are specified in my flags() method that looks like this:

def flags(self, index):  # Qt was imported from PyQt4.QtCore
    if index.column() < 2:
        return Qt.ItemIsEditable | Qt.ItemIsEnabled | \
               Qt.ItemIsSelectable
    else:
        return Qt.ItemIsEnabled | Qt.ItemIsSelectable

Cells in the first two columns are marked as editable just like I want.

What I want to do:

However when double clicking the cell to trigger the editing the contained text is deleted and an empty field is shown.

Example of editing a cell

But I don't want to delete & replace the contained text because the contained text could be very long and shouldn't be retyped. I just want to edit what is already contained. When double-clicked the cell should be editable with the previously contained text inside (maybe already selected).

The Question:

How can I achieve this behavior? Do I need to edit my flags method and specify different properties for these cells?


Solution

  • You have a few options.

    No data is appearing in the cells during editing because you likely haven't set any data on the Qt.EditRole for each item in your model. The QTableWidget's do this be default.

    Another way of doing this is by using a QItemDelegate. This will allow you to manually create the editor widget and initialize it before it appears in the QTableView. You can use the display role text if the edit text hasn't been populated.

    class MyDelegate(QtGui.QItemDelegate):
    
        def createEditor(self, parent, option, index):
            if index.column() == 2:
                return super(MyDelegate, self).createEditor(parent, option, index)
            return None
    
        def setEditorData(self, editor, index):
            if index.column() == 2:
                # Gets display text if edit data hasn't been set.
                text = index.data(Qt.EditRole) or index.data(Qt.DisplayRole)
                editor.setText(text)         
    
    delegate = MyDelegate()
    tableview.setItemDelegate(delegate)