Search code examples
pythonpyqtpyqt5qtreeviewqabstracttablemodel

Is it possible to add dict() or list() to insertRows() in QTreeView


I have this TreeItem:

class QJsonTreeItem(object):
def __init__(self, data, parent=None):
    self._parent = parent

    self._key = ""
    self._value = ""
    self._type = None
    self._children = list()
    self.itemData = data

...

def data(self, column):
    if column is 0:
        return self.key
    elif column is 1:
        return self.value

def setData(self, column, value):
    if column is 0:
        self.key = value
    if column is 1:
        self.value = value

...

def insertChildren(self, position, rows, columns):
    if position < 0 or position > len(self._children):
        return False

    for row in range(rows):
        data = [None for v in range(columns)]
        item = QJsonTreeItem(data, self)
        self._children.insert(position, item)

    return True

...

And custom QAbstractItemModel:

class QJsonTreeModel(QAbstractItemModel):

def __init__(self, parent=None):
    super(QJsonTreeModel, self).__init__(parent)

    self._rootItem = QJsonTreeItem(["Key", "Value"])
    self._headers = ("Key", "Value")

...

def data(self, index, role):
    if not index.isValid():
        return None

    if role != Qt.DisplayRole and role != Qt.EditRole:
        return None

    item = index.internalPointer()

    if role == Qt.DisplayRole or role == Qt.EditRole:
        if index.column() == 0:
            return item.data(index.column())

        if index.column() == 1:
            return item.value
    return None

def getItem(self, index):
    if index.isValid():
        item = index.internalPointer()
        if item:
            return item

    return self._rootItem

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

    return False

def parent(self, index):
    if not index.isValid():
        return QModelIndex()

    childItem = index.internalPointer()
    parentItem = childItem.parent()

    if parentItem == self._rootItem:
        return QModelIndex()

    return self.createIndex(parentItem.row(), 0, parentItem)


...

def insertRows(self, position, rows, parent, *args, **kwargs):
    parentItem = self.getItem(parent)
    
    self.beginInsertRows(parent, position, position + rows - 1)
    success = parentItem.insertChildren(position, rows, self._rootItem.columnCount())
    self.endInsertRows()

    return success

And in my MainWindow file there is a button for adding new items in QTreeView which looks like this:

self.treeView = QTreeView()

self.model = QJsonTreeModel()
self.treeView.setModel(self.model)

...

rightClickMenu = QMenu()            
actionAddItem = rightClickMenu.addAction(self.tr("Add Item"))
actionAddItem.triggered.connect(partial(self.treeAddItem))

...

def treeAddItem(self):
    try:
        index = self.treeView.selectionModel().currentIndex()
        parent = index.parent()

        if self.model.data(parent, Qt.EditRole) == None:
            if not self.model.insertRow(index.row() + 1, parent):
                return

            for column in range(self.model.columnCount(parent)):
                child = self.model.index(index.row() + 1, column, parent)
                self.model.setData(child, "[No data]", Qt.EditRole)
        else:
            pass
    except Exception as exception:
        QMessageBox.about(self, "Exception", "Exception in treeAddItem() function: " + str(exception))  
        return

The question is can I somehow add not an "[No data]" string for QtreeView, but fo example an empty dict() or list()? As far as I understand it only adds an empty strings to the QTreeView, but my task still needs dictionaries and list. If it`s not possible my main idea is to get full tree back to dictionary and to work directly with dictionary items and then load back changed dict to tree, but it seems kinda "bad style".

Can someone help me with this task or offer another idea?


Solution

  • The soultion I did is this:

    def setData(self, index, value, role=Qt.EditRole):
        if role == Qt.EditRole:
            item = index.internalPointer()
            item.setData(index.column(), value)
            self.dataChanged.emit(index, index, [Qt.EditRole])
            return True
        if role == Qt.DisplayRole:
            item = index.internalPointer()
            item.setData(index.column(), dict())
            self.dataChanged.emit(index, index, [Qt.EditRole])
            return True
        if role == Qt.ToolTipRole:
            item = index.internalPointer()
            item.setData(index.column(), list())
            self.dataChanged.emit(index, index, [Qt.EditRole])
            return True
        return False