Search code examples
c++qtsubclassingqabstractitemmodel

Subclassing: QAbstractItemModel has no member


I am relatively new to C++ and the Qt Framework. I tried to implement a simple QTableView with a custom model derived from QAbstractListModel.

If I call

model->appendRow("Test");

in my main application, everything works perfectly fine. However, if I call

table->model()->appendRow("Test");

I get the following build-error:

'class QAbstractItemModel' has no member named 'appendRow'
         table->model()->appendRow("Test");
                     ^

What am I missing?

Sourcecode:

main.c

#include <QApplication>
#include <QTableView>
#include "exercises.h"


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

    QTableView *table = new QTableView();
    exercisesModel *model = new exercisesModel();
    table->setModel(model);

    model->appendRow("Test"); //why does this work...
    table->model()->appendRow("Test"); //...and this doesn't?

    table->show();

    return a.exec();
} 

exercises.h

#ifndef EXERCISES_H
#define EXERCISES_H

#include <QWidget>
#include <QAbstractListModel>

class exercisesModel : public QAbstractListModel
{
public:
    exercisesModel(QObject *parent = 0);
    int rowCount(const QModelIndex &parent) const;
    QVariant data(const QModelIndex &index, int role) const;
    bool appendRow(QString data);
private:
    QList <QString> lst;

};

#endif // EXERCISES_H

exercises.c

#include "exercises.h"
#include <QDebug>


exercisesModel::exercisesModel(QObject *parent) : QAbstractListModel(parent){
}

int exercisesModel::rowCount(const QModelIndex &parent) const{
    Q_UNUSED(parent);
    return this->lst.size();

}

QVariant exercisesModel::data(const QModelIndex &index, int role) const{
    if(this->lst.size() != 0){
        if (role == Qt::DisplayRole){
            return this->lst[index.row()];
        }

        return QVariant();
    }
    return QVariant();

}

bool exercisesModel::appendRow(QString data){
    int lastElemPos = this->lst.size();
    beginInsertRows(QModelIndex(), lastElemPos, lastElemPos);
    this->lst << data;

    endInsertRows();

    return true;

}

Solution

  • The QTableView::model() member function returns a pointer to a QAbstractItemModel. That is all the compiler knows about the type at the time you call table->model()->appendRow("Test"). It doesn't know that your derived model is what is actually being pointed to. There are a few ways this could be handled.

    One way is to use a cast:

    static_cast<exercisesModel*>(table->model())->appendRow("Test")
    

    Now you are explicitly telling the compiler "I know that the actual type of the object is exercisesModel", so it can treat it appopriately.

    As noted by Kuba Ober, Qt has its own cast that will verify that the type is correct

    qobject_cast<exercisesModel*>(table->model())->appendRow("Test")
    

    This is better than static_cast, but this check will only be done at run-time, and the more problems you can catch during compiling, the better.

    The best option may be to keep the pointer to your exercisesModel and use that, so there is no question about what the underlying type is.