paulm
paulm

Reputation: 5892

QAbstractItemModel confused about index/parent and data functions

I have the following simple model example:

#include <QtGui/QApplication>
#include <QtGui/QTreeView>
#include <QAbstractItemModel>

class TestModel : public QAbstractItemModel
{
public:
    TestModel()
    {
        SetUpData();
    }

    virtual QModelIndex index(int row, int column, const QModelIndex& parent) const
    {
        if ( parent.isValid())
        {
            // child
            return createIndex( row, column, (void*)&mData[row].mChildren[column]);
        }
        // root
        return createIndex( row, column, (void*)&mData[row]);
    }

    virtual QModelIndex parent(const QModelIndex& child) const
    {
        ModelData* data = (ModelData*)child.internalPointer();

        // find out where "data" is in the mData vector structure
        for ( size_t i=0; i<mData.size(); ++i )
        {
            for ( size_t j=0; j<mData[i].mChildren.size(); ++j )
            {
                if ( &mData[i].mChildren[j] == data )
                {
                    // I think this is correct, return the parent row at col 0?
                    return createIndex( i, 0, (void*)&mData[i].mChildren[j]);
                }
            }
        }
        return QModelIndex();
    }

    virtual int rowCount(const QModelIndex& parent) const
    {
        if ( parent.isValid() )
        {
            // Per root node size
            return mData[parent.row()].mChildren.size();
        }

        // Root size
        return mData.size();
    }

    virtual int columnCount(const QModelIndex& parent) const
    {
        // The "parent" nodes should have two columns, the children should have 1
        if ( parent.isValid() )
        {
            // Root
            return 1;
        }
        // Children
        return 2;
    }

    virtual QVariant data(const QModelIndex& index, int role) const
    {
        if ( role == Qt::DisplayRole && index.isValid() )
        {
            if ( index.isValid() )
            {
                // I think col and row are the wrong way around, but will crash if swapped
                return mData[index.column()].mChildren[index.row()].mName;
            }
            else
            {
                // this never happens because "RootN" is never displayed
                return mData[index.column()].mName;
            }
        }
        return QVariant();
    }

private:
    // The "real" data that this Qt model is providing an interface to
    struct ModelData
    {
        QString mName;
        std::vector< ModelData > mChildren;
    };

    std::vector< ModelData > mData;

    void SetUpData()
    {
        for ( int i=0; i<3; ++i )
        {
            ModelData root;
            root.mName = "Root" + QString::number( i+1 );

            for ( int j=0; j<10; ++j )
            {
                ModelData node;
                node.mName = "Node" + QString::number( j+1 );
                root.mChildren.push_back( node );
            }
            mData.push_back( root );
        }
    }
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    TestModel* model = new TestModel();
    QTreeView* tv = new QTreeView();

    tv->setModel( model );
    tv->show();

    int ret = a.exec();

    delete tv;
    delete model;

    return ret;
}

What I'm trying to do here is create a model which has the following structure:

Root1
 |-Node1-10
 |
Root2
 |-Node1-10
 |
Root3
 |-Node1-10

However I end up with this:

output

I'm really confused about how index/parent and data are supposed to be working. Obviously I don't understand it because my output is incorrect.

I thought that for example, Root1, Node3 would cause index to be called with row = 0, col=2, at which point I call createIndex with 0,2 and the pointer to that element?

And for parent() return QModelIndex if parent is valid as this means its a RootN element, then return createIndex to create an index to the parent if its not a root element.

Finally for data I figured this just returns the display string for the UI for the given row/column?

Upvotes: 0

Views: 4962

Answers (1)

cmannett85
cmannett85

Reputation: 22356

I thought that for example, Root1, Node3 would cause index to be called with row = 0, col=2, at which point I call createIndex with 0,2 and the pointer to that element?

No. Your tree has only two columns: col 0 shows the tree hierarchy, and col 1 displays the labels again. So calling col 2 is just invalid.

Root1, Node3 should have a row=2 col=(1/2, whichever you wanted) and a parent index equal to row=0, col=(1/2) with an invalid parent (an invalid parent means you are at root level).

What data(..) returns depends on what role is passed to it, see the documentation for types you should be interested in.

Upvotes: 2

Related Questions