Tableview delete rows works only one time

Heads up! You've already completed this tutorial.

Aashish_Gogna | 2022-08-09 11:10:54 UTC | #1

Hello Team,

I have created Qtreeview and Qtableview and set their models to respective Abstract classes. Functionality is: doubleclclicking on an element present in the treeview will create a new row in the tableview with some additional columns. One function in My code is to delete these entries when a button is clicked, which successfully deletes the entire table only once per run, and gives no result for further clicks on delete button even if the entries are present.

delete rows code is:

model.removeRows(position=0, rows=model.rowCount(0))

where removeRows function in tablemodel is written as:

    def removeRows(self, position, rows=1, index=QtCore.QModelIndex()):
            "\n\t\t ...removeRows() Starting position: '%s'" % position, 'with the total rows to be deleted: ', rows)
        self.beginRemoveRows(QtCore.QModelIndex(), position, position + rows - 1)

Please suggest why the deletion activity deletes the rows only once per run and why the rowcount is always an increasing number even though the rows have already been deleted?

the code is :slight_smile:

class TableModel(QtCore.QAbstractTableModel):
    def __init__(self, data, data_header):
        super(TableModel, self).__init__()
        self._data = data
        self.header = data_header

    def data(self, index, role):
        if role == Qt.DisplayRole:
            # See below for the nested-list data structure.
            # .row() indexes into the outer list,
            # .column() indexes into the sub-list
            return self._data[index.column()][index.row()]
        elif role == Qt.EditRole:
            return self._data[index.column()][index.row()]
        elif role == Qt.BackgroundRole:
            # See below for the data structure.
            value = self._data[index.column()][index.row()]
            if index.column() == 6:
                if value == "Not Started":
                    return QtGui.QColor("yellow")
                elif value == "Started":
                    return QtGui.QColor("orange")
                elif value == "Passed":
                    return QtGui.QColor("green")
                elif value == "Failed":
                    return QtGui.QColor("red")

        elif role == Qt.TextAlignmentRole:
            value = self._data[index.column()][index.row()]
            if isinstance(value, int) or isinstance(value, float):
                # Align right, vertical middle.
                return Qt.AlignVCenter + Qt.AlignRight

        elif role == Qt.ForegroundRole:
            value = self._data[index.column()][index.row()]
            if (
                    (isinstance(value, int) or isinstance(value, float))
                    and value < 0
                return QtGui.QColor('red')
            return QtCore.QVariant()

    def flags(self, index):

        if index.column() == 0 or index.column() == 1 or index.column() == 6 or index.column() == 7:
            return Qt.ItemIsSelectable | Qt.ItemIsEnabled
            return Qt.ItemIsSelectable | Qt.ItemIsEnabled | Qt.ItemIsEditable

    def update(self, dataIn, data_header):
        print('Updating Model')
        self._data = dataIn
        self.header = data_header
        print('Datatable : {0}'.format(self._data))

    def rowCount(self, index):
        # The length of the outer list.
        return len(self._data[0])

    def columnCount(self, index):
        # The following takes the first sub-list, and returns
        # the length (only works if all rows are an equal length)
        return len(self._data)

    def headerData(self, col, orientation, role):
        if orientation == Qt.Horizontal and role == Qt.DisplayRole:
            return self.header[col]
        return None

    def setData(self, index, value, role=QtCore.Qt.EditRole):
        if index.isValid() and 0 <= index.row():
            if role == QtCore.Qt.EditRole:
                self._data[index.column()][index.row()] = value
                print("edit", value)
                self.dataChanged.emit(index, index)  # NOT WORKING
                return True
                return False
            return False

    def addrow(self):
        # print(self.rowCount(0))
        self.beginInsertRows(QtCore.QModelIndex(), 0, 0)
        ret = (self.insertRows(self.rowCount(0), 1))
        # print(ret)

    def removeRows(self, position, rows=1, index=QtCore.QModelIndex()):
            "\n\t\t ...removeRows() Starting position: '%s'" % position, 'with the total rows to be deleted: ', rows)
        self.beginRemoveRows(QtCore.QModelIndex(), position, position + rows - 1)
        # del self._data[position]
        # self.items = self.items[:position] + self.items[position + rows:]

    def delete_row(self, index):
        self.removeRows(index.row(), 1, QtCore.QModelIndex())

martin | 2021-07-23 14:47:09 UTC | #2

Hey! I'm a bit confused by your example code as there is nothing there to actually remove the data from the model. In the second (larger block) there are lines to do this, but they are commented out.

The beginRemoveRows and endRemoveRows is just there to notify the view that the data is being modified, you still need to make the modifications to the data yourself.

For a list of rows, you can just delete the start index n times (since subsequent elements will shift up). For example...

self.beginRemoveRows(QtCore.QModelIndex(), position, position + rows - 1)
for _ in range(rows):
    del self._data[position]

1:1 Coaching & Tutoring for your Python GUIs project
Martin Fitzpatrick Python GUIs Coaching & Training
60 mins ($195) More info

1:1 Python GUIs Coaching & Training

Comprehensive code reviewBugfixes & improvements • Maintainability advice and architecture improvements • Design and usability assessment • Suggestions and tips to expand your knowledgePackaging and distribution help for Windows, Mac & Linux • Find out more.

Well done, you've finished this tutorial! Mark As Complete
[[ user.completed.length ]] completed [[ user.streak+1 ]] day streak

Tableview delete rows works only one time was written by Martin Fitzpatrick .

Martin Fitzpatrick has been developing Python/Qt apps for 8 years. Building desktop applications to make data-analysis tools more user-friendly, Python was the obvious choice. Starting with Tk, later moving to wxWidgets and finally adopting PyQt.