Klidrack Klidrack - 28 days ago 15
C++ Question

Qt Qml Error: Unable to assign [undefined] to QString in a subclassed QAbstractItemModel for Qml TreeView

I try to create a custom module for the Qml TreeView and I used Simpel Treeview Example as foundation, but I always get "unabe to assign [undefined] to QString".

Here some infos u might need:

Displayed view

Qml:

import QtQuick 2.0
import QtQuick.Controls 1.4
import cci.screenshotCreator.StructureDataModel 1.0

TreeView {
id: root
state: "closed"
TableViewColumn {
role: "folderName"
title: "Ordnerstruktur"
}
model: StructureDataModel{
id: dataModel
}

itemDelegate: Item {
height: 30
Rectangle {
id: rectangle
color: styleData.selected ? "lightgray" : "#ffffff"
border.width: styleData.selected ? 2 : 1
border.color: styleData.selected ? "lightblue" : "#ababab"
anchors.fill: parent
}

Text {
id: folderText
text: dataModel.folderName
fontSizeMode: Text.Fit
anchors.fill: parent
font.pointSize: 12
verticalAlignment: Text.AlignLeft
}


C++:

#include "structuredatamodel.h"

structureDataModel::structureDataModel(QObject *parent)
: QAbstractItemModel(parent)
{
QList<QVariant> rootData;
rootData << "/";
rootItem = new StructureItem(rootData);
setupModelData(rootItem);
}

structureDataModel::~structureDataModel()
{
delete rootItem;
}

QModelIndex structureDataModel::index(int row, int column, const QModelIndex &parent) const
{
if(!hasIndex(row, column, parent))
return QModelIndex();

StructureItem *parentItem;

if(!parent.isValid())
parentItem = rootItem;
else
parentItem = static_cast<StructureItem*>(parent.internalPointer());

StructureItem *childItem = parentItem->child(row);
if(childItem)
return createIndex(row, column, childItem);
else
return QModelIndex();
}

QHash<int, QByteArray> structureDataModel::roleNames() const
{
QHash<int, QByteArray> roles;
roles[structureRoles::folderName] = "folderName";
return roles;
}

QModelIndex structureDataModel::parent(const QModelIndex &index) const
{
if(!index.isValid())
return QModelIndex();

StructureItem *childItem = static_cast<StructureItem*>(index.internalPointer());
StructureItem *parentItem = childItem->parentItem();

if (parentItem == rootItem)
return QModelIndex();

return createIndex(parentItem->row(), 0, parentItem);
}

int structureDataModel::rowCount(const QModelIndex &parent) const
{
StructureItem *parentItem;
if(parent.column() > 0)
return 0;

if(!parent.isValid())
parentItem = rootItem;
else
parentItem = static_cast<StructureItem*>(parent.internalPointer());

return parentItem->childCount();
}

int structureDataModel::columnCount(const QModelIndex &parent) const
{
if(parent.isValid())
return static_cast<StructureItem*>(parent.internalPointer())->columnCount();
else
return rootItem->columnCount();
}

QVariant structureDataModel::data(const QModelIndex &index, int role) const
{
if(!index.isValid())
return QVariant();

if(role != structureRoles::folderName)
return QVariant();

StructureItem *item = static_cast<StructureItem*>(index.internalPointer());


return item->data(index.column()).toString();
}


Qt::ItemFlags structureDataModel::flags(const QModelIndex &index) const
{
if(!index.isValid())
return 0;

return QAbstractItemModel::flags(index);
}

QVariant structureDataModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (orientation == Qt::Horizontal && role == structureRoles::folderName)
return rootItem->data(section);

return QVariant();
}


void structureDataModel::setupModelData(StructureItem *parent)
{
QList<QVariant> data;
data << "Test";
StructureItem *child = new StructureItem(data, parent);
parent->appendChild(child);
}


The StructureItem is is the same as TreeItem (just a different name :) )
I made my own setupModelData so that model only have one row as root point.
Later I would like to have a editable treeview but for now a working read-only treeView should work right now.
I suspect that it has something to with the setupModelData or making the c++ visible for qml.

PS: I added qmlRegisterType("cci.screenshotCreator.StructureDataModel", 1, 0, "StructureDataModel"); to the main file to register the cpp class.

Minimal Application for testing:
https://pastebin.com/u/Klidrack (all files of my pastebin profile) :)

Answer Source

Oh, didn't saw it at first look. There is diference between ListView's and TreeView's delegated components in QML. In TreeView you have itemDelegate and all data are expanded through styleData properties.

in your case this should look like this:

itemDelegate: Item
    {
        height: 30
        Rectangle
        {
            id: rectangle
            color: styleData.selected ? "lightgray" : "#ffffff"
            border.width: styleData.selected ? 2 : 1
            border.color: styleData.selected ? "lightblue" : "#ababab"
            anchors.fill: parent
        }

        Text
        {
            id: folderText
            text: styleData.value
            fontSizeMode: Text.Fit
            anchors.fill: parent
            font.pointSize: 12
            verticalAlignment: Text.AlignLeft
        }
    }