Starting work with QTreeView, QAbstractItemModel



  • Hello.

    I am having problems with forcing QAbstractItemModel to work with QTreeView. I am aiming to create a simple contact list, and to do it I try to implement a very basic functionalities and then to extend it - but I'm struggling even with it. The code is compiling but nothing shows up in the widget.

    As a startpoint I chose Simple Tree example from "here":http://qt-project.org/doc/qt-4.8/itemviews-simpletreemodel.html .
    I have changed the Item to contain only QString, but after adding items, nothing is presented - as if QTreeView didn't read any data from model.

    the code is as follows:
    main.cpp
    @#include <QtGui/QApplication>
    #include <QTreeView>
    #include <QDebug>
    #include "rostermodel.h"
    #include "rosteritem.h"

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

    QTreeView *view = new QTreeView;
    
    RosterItem *it = new RosterItem(QString("Kris"));
    RosterModel *model = new RosterModel();
    model->addItem(it);
    it = new RosterItem(QString("Adam"));
    model->addItem(it);
    it = new RosterItem(QString("Sylvia"));
    model->addItem(it);
    view->setModel(model);
    view->show();
    
    return a.exec&#40;&#41;;
    

    }@

    rosteritem.h
    @class RosterItem
    {
    public:
    RosterItem(QString name, RosterItem *parent=0);
    ~RosterItem();

    void appendChild(RosterItem *cont);
    RosterItem *child(int row);
    int childCount() const;
    int columnCount() const;
    QVariant data() const;
    int row() const;
    RosterItem *parent();
    

    private:
    QList<RosterItem*> childItems;
    QString name;
    RosterItem *parentItem;

    };@

    rosteritem.cpp
    @#include "rosteritem.h"

    RosterItem::RosterItem(QString nam, RosterItem *parent):
    name(nam),parentItem(parent)
    {
    }

    RosterItem::~RosterItem()
    {
    qDeleteAll(childItems);
    }

    void RosterItem::appendChild(RosterItem *cont)
    {
    childItems.append(cont);
    }

    RosterItem* RosterItem::child(int row)
    {
    return childItems.value(row);
    }

    int RosterItem::childCount() const
    {
    return childItems.size();
    }

    int RosterItem::columnCount() const
    {
    return 1;
    }

    QVariant RosterItem::data() const
    {
    return name;
    }

    RosterItem* RosterItem::parent()
    {
    return parentItem;
    }

    int RosterItem::row() const
    {
    if(parentItem)
    {
    return parentItem->childItems.indexOf(const_cast<RosterItem*>(this));
    }
    return 0;
    }@

    rostermodel.h
    @#include <QAbstractItemModel>
    #include <QModelIndex>
    #include "rosteritem.h"

    class RosterModel : public QAbstractItemModel
    {
    Q_OBJECT
    public:
    explicit RosterModel(QObject parent = 0);
    ~RosterModel();
    Qt::ItemFlags flags(const QModelIndex &index) const;
    QVariant data(const QModelIndex &index, int role) const;
    void addItem(RosterItem
    item);
    QModelIndex parent(const QModelIndex &child) const;
    QModelIndex index(int row, int column, const QModelIndex &parent) const;
    int rowCount(const QModelIndex &parent) const;
    int columnCount(const QModelIndex &parent) const;
    QVariant headerData(int section, Qt::Orientation orientation,
    int role) const;

    private:
    RosterItem *root;
    };@

    rostermodel.cpp
    @#include "rostermodel.h"

    RosterModel::RosterModel(QObject *parent) :
    QAbstractItemModel(parent)
    {
    root=new RosterItem(QString("ROSTER"));
    }

    RosterModel::~RosterModel()
    {
    delete root;
    }

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

    return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
    

    }

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

    if (role != Qt::DisplayRole)
        return QVariant();
    
    RosterItem *item = static_cast<RosterItem*>(index.internalPointer());
    
    return item->data();
    

    }

    void RosterModel::addItem(RosterItem *item)
    {
    root->appendChild(item);
    }

    QVariant RosterModel::headerData(int section, Qt::Orientation orientation,
    int role) const
    {
    return root->data();
    }

    QModelIndex RosterModel::parent(const QModelIndex &child) const
    {
    if (!child.isValid())return QModelIndex();

    RosterItem *childItem = static_cast<RosterItem*>(child.internalPointer());
    RosterItem *parentItem = childItem->parent();
    
    if (parentItem == root)
        return QModelIndex();
    
    return createIndex(parentItem->row(), 0, parentItem);
    

    }

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

    RosterItem *parentItem;
    
    if (!parent.isValid())
        parentItem = root;
    else
        parentItem = static_cast<RosterItem*>(parent.internalPointer());
    
    RosterItem *childItem = parentItem->child(row);
    if (childItem) return createIndex(
                row, column, childItem);
    else return QModelIndex();
    

    }

    int RosterModel::columnCount(const QModelIndex &parent) const
    {
    if(parent.isValid())return 1;
    else return 0;
    }

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

    if (!parent.isValid())
        parentItem = root;
    else
        parentItem = static_cast<RosterItem*>(parent.internalPointer());
    
    return parentItem->childCount();
    

    }
    @

    Thanks in advance for any advices.



  • Hi lauku,

    There were a few issues with your code:

    1. Your columnCount() was always returning 0 (i.e. no columns) because you required a valid parent to return 1 and "root" has no valid parents...

    2. None of your RosterItem's had a parent which meant that in your parent() function, when you call createIndex(), the first argument was invalid.

    3. Your headerData() function didn't check the role for which data was requested so you would never have had a visible header:

    I've corrected all these errors as shown below (see lines 8-10, 47-48 and 85-86 in rostermodel.cpp):

    main.cpp
    @
    #include <QtGui/QApplication>
    #include <QTreeView>
    #include <QDebug>
    #include "rostermodel.h"
    #include "rosteritem.h"

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

    QTreeView *view = new QTreeView;
    RosterModel *model = new RosterModel();
    view->setModel(model);
    view->show();
    
    return a.exec&#40;&#41;;
    

    }
    @

    rostermodel.cpp
    @
    #include "rostermodel.h"

    RosterModel::RosterModel(QObject *parent) :
    QAbstractItemModel(parent)
    {
    root=new RosterItem(QString("ROSTER"));

    root->appendChild(new RosterItem(QString("Kris"), root));
    root->appendChild(new RosterItem(QString("Adam"), root));
    root->appendChild(new RosterItem(QString("Sylvia"), root));
    

    }

    RosterModel::~RosterModel()
    {
    delete root;
    }

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

    return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
    

    }

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

    if (role != Qt::DisplayRole)
        return QVariant();
    
    RosterItem *item = static_cast<RosterItem*>(index.internalPointer());
    
    return item->data();
    

    }

    void RosterModel::addItem(RosterItem *item)
    {
    root->appendChild(item);
    }

    QVariant RosterModel::headerData(int section, Qt::Orientation orientation,
    int role) const
    {
    if(orientation==Qt::Horizontal && role==Qt::DisplayRole) return root->data();
    return QVariant();
    }

    QModelIndex RosterModel::parent(const QModelIndex &child) const
    {
    if (!child.isValid())return QModelIndex();

    RosterItem *childItem = static_cast<RosterItem*>(child.internalPointer());
    RosterItem *parentItem = childItem->parent();
    
    if (parentItem == root)
        return QModelIndex();
    
    return createIndex(parentItem->row(), 0, parentItem);
    

    }

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

    RosterItem *parentItem;
    
    if (!parent.isValid())
        parentItem = root;
    else
        parentItem = static_cast<RosterItem*>(parent.internalPointer());
    
    RosterItem *childItem = parentItem->child(row);
    if (childItem) return createIndex(
                row, column, childItem);
    else return QModelIndex();
    

    }

    int RosterModel::columnCount(const QModelIndex &parent) const
    {
    if(parent.isValid()) return static_cast<RosterItem*>(parent.internalPointer())->columnCount();
    return root->columnCount();
    }

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

    if (!parent.isValid())
        parentItem = root;
    else
        parentItem = static_cast<RosterItem*>(parent.internalPointer());
    
    return parentItem->childCount();
    

    }
    @

    Hope this helps ;o)


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.