insertColumns (QAbstractTableModel) does not work correctly)

Encountered a problem: when trying to add a column after adding it N-rows(in my example 2), it turns out that:

enter a description of the image here

Fig.1. Added 2 lines, until everything is OK

enter a description of the image here

Fig.2. After adding 1 columns. The column was added by shifting the existing ones to the right, but pay attention to 2 column rows 1 and 2. I've been fighting this all night, until nothing happens. I can understand.

import sys
from PyQt5.QtWidgets import QApplication, QTableView, QPushButton
from PyQt5.QtCore import QAbstractTableModel
from PyQt5.QtCore import Qt, QModelIndex
from PyQt5.QtGui import QPixmap, QImage, QIcon, QColor
import random


data = [[random.randint(1, 100) for i in range(5)] for i in range(5)]

headers = [
    'Column 1',
    'Column 2',
    'Column 3',
    'Column 4',
    'Column 5'
]


class TestModel(QAbstractTableModel):
    def __init__(self, data=[[]], headers=[], parent=None):
        super().__init__(parent)
        self.__data = data
        self.__headers = headers
        self.__image_file = 'Notepad/icons/save_file.png'
        self.getPixmap()

    def getPixmap(self):
        try:
            with open(self.__image_file):
                image = QImage(self.__image_file)
                self.__pixmap = QPixmap(image)
        except FileNotFoundError:
            self.__pixmap = QPixmap(26, 26)
            self.__pixmap.fill(QColor('green'))
            print(self.__pixmap)

    def rowCount(self, parent=QModelIndex()):
        return len(self.__data)

    def columnCount(self, parent=QModelIndex()):
        return len(self.__data[0])

    def flags(self, index):
        return Qt.ItemIsEnabled|Qt.ItemIsSelectable|Qt.ItemIsEditable

    def data(self, index, role):
        if role == Qt.DisplayRole:
            row = index.row()
            column = index.column()
            return self.__data[row][column]

        if role == Qt.EditRole:
            row = index.row()
            column = index.column()
            return self.__data[row][column]

        if role == Qt.ToolTipRole:
            row = index.row()
            column = index.column()
            return self.__data[row][column]

        if role == Qt.DecorationRole:
            icon = QIcon(self.__pixmap)
            return icon

    def setData(self, index, value, role=Qt.EditRole):
        if role == Qt.EditRole:
            row = index.row()
            column = index.column()
            self.__data[row][column] = value
            self.dataChanged.emit(index, index)
            return True
        return False

    def headerData(self, section, orientation, role):
        if role == Qt.DisplayRole:
            if orientation == Qt.Horizontal:
                    if section < len(self.__headers):
                        return self.__headers[section]
                    else:
                        return 'Not implemented'
            else:
                return 'Row №' + str(section + 1)

    def insertRows(self, position, rows, parent=QModelIndex()):
        self.beginInsertRows(parent, position, position + rows - 1)
        default_row = ['New row' for i in range(self.columnCount(None))]
        for j in range(rows):
            self.__data.insert(position, default_row)
        self.endInsertRows()
        return True

    def insertColumns(self, position, columns, parent=QModelIndex()):
        self.beginInsertColumns(parent, position, position + columns - 1)
        for row in self.__data:
            for i in range(columns):
                row.insert(position, 'New col')
        self.endInsertColumns()
        return True


if __name__ == '__main__':
    app = QApplication(sys.argv)

    model = TestModel(data, headers)

    table_view = QTableView()
    table_view.setModel(model)
    table_view.show()
    table_view.resize(700, 300)

    button1 = QPushButton('Add col')
    button1.clicked.connect(lambda: model.insertColumns(0, 1))
    button1.show()
    button1.move(100, 100)

    button2 = QPushButton('Add row')
    button2.clicked.connect(lambda: model.insertRows(0, 2))
    button2.show()
    button2.move(100, 200)

    sys.exit(app.exec_())
Author: S. Nick, 2021-01-21

1 answers

Try this way:

import sys
import random
from PyQt5.QtWidgets import QApplication, QTableView, QPushButton, \
    QWidget, QGridLayout
from PyQt5.QtCore import QAbstractTableModel, Qt, QModelIndex
from PyQt5.QtGui import QPixmap, QImage, QIcon, QColor


class TestModel(QAbstractTableModel):
    def __init__(self, data=[[]], headers=[], parent=None):
        super().__init__(parent)
        
        self.__data = data
        self.__headers = headers
        self.__image_file = 'Ok.png'                            # 'Notepad/icons/save_file.png'
        self.getPixmap()

    def getPixmap(self):
        try:
            with open(self.__image_file):
                image = QImage(self.__image_file)
                self.__pixmap = QPixmap(image)
        except FileNotFoundError:
            self.__pixmap = QPixmap(26, 26)
            self.__pixmap.fill(QColor('green'))
            print(self.__pixmap)

    def rowCount(self, parent=QModelIndex()):
        return len(self.__data)

    def columnCount(self, parent=QModelIndex()):
        return len(self.__data[0])

    def flags(self, index):
        return Qt.ItemIsEnabled|Qt.ItemIsSelectable|Qt.ItemIsEditable

    def data(self, index, role):
        if role == Qt.DisplayRole:
            row = index.row()
            column = index.column()
            return self.__data[row][column]

        if role == Qt.EditRole:
            row = index.row()
            column = index.column()
            return self.__data[row][column]

        if role == Qt.ToolTipRole:
            row = index.row()
            column = index.column()
            return self.__data[row][column]

        if role == Qt.DecorationRole:
            icon = QIcon(self.__pixmap)
            return icon

    def setData(self, index, value, role=Qt.EditRole):
        if role == Qt.EditRole:
            row = index.row()
            column = index.column()
            self.__data[row][column] = value
            self.dataChanged.emit(index, index)
            return True
        return False

    def headerData(self, section, orientation, role):
        if role == Qt.DisplayRole:
            if orientation == Qt.Horizontal:
                    if section < len(self.__headers):
                        return self.__headers[section]
                    else:
                        return 'Not implemented'
            else:
                return 'Row №' + str(section + 1)

    def insertRows(self, position, rows, parent=QModelIndex()):
        #print(f'\nrows={rows}, position={position} ---------------')
        self.beginInsertRows(parent, position, position + rows - 1)
        #default_row = [f'row{i}' for i in range(self.columnCount(None))]
        #print(f'default_row={default_row} ===============')
        for j in range(rows):
            default_row = [f'row{i}-{j}' for i in range(self.columnCount(None))]
            self.__data.insert(position, default_row)
        self.endInsertRows()
        return True
    '''
    def insertColumns222(self, position, columns, parent=QModelIndex()):
        self.beginInsertColumns(parent, position, position + columns - 1)
        for row in self.__data:
            for i in range(columns):
                row.insert(position, f'New col: {row}-{i}')
        self.endInsertColumns()
        return True
    '''
# +++
    def insertColumns(self, position, columns, parent=QModelIndex()):
        self.beginInsertColumns(parent, position, position + columns - 1)
        """ self.beginInsertColumns(index, first, last) """
        rowCount = len(self.__data)
        #print(f' rowCount={rowCount}, columns={columns}')
        for i in range(columns):
            #print(f'  columns={i}')
            for j in range(rowCount):                          # Преребираем Строки
                #print(f'  rowCount={j}, ?? {self.__data[j]}')
                self.__data[j].insert(position, "new cell")
        self.endInsertColumns()
        return True


class MyWindow(QWidget):
    def __init__(self):
        super().__init__()

        data = [[random.randint(1, 100) for i in range(5)] for i in range(5)]
        headers = ['Column 1', 'Column 2', 'Column 3', 'Column 4', 'Column 5']        

        self.table_view = QTableView()
        self.model = TestModel(data, headers) # MyTableModel(data, headers)
        self.table_view.setModel(self.model)

        button1 = QPushButton('Add col')
        button1.clicked.connect(lambda: self.model.insertColumns(0, 1))
        button2 = QPushButton('Add row')
        button2.clicked.connect(lambda: self.model.insertRows(0, 2))               # 2 ?

        grid = QGridLayout(self) 
        grid.addWidget(self.table_view, 0, 0, 1, 2)
        grid.addWidget(button1, 1, 0)
        grid.addWidget(button2, 1, 1)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    w = MyWindow()
    w.resize(700, 300)
    w.show()
    sys.exit(app.exec_())

enter a description of the image here

enter a description of the image here

 0
Author: S. Nick, 2021-01-22 00:09:55