Search code examples
qtqt4qtreeviewqabstractitemmodel

Why is this QAbstractItemModel based model not working?


I create a simple QMainWindow app as follows:

The header file:

//mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H


#include <QAbstractItemModel>
#include <QTreeView>
#include <QVBoxLayout>


#include <QMainWindow>

namespace Ui {
class MainWindow;
}



class MyTreeModel : public QAbstractItemModel
{
public:
    Q_OBJECT

public:
    MyTreeModel(QObject *parent=NULL);

    QModelIndex parent(const QModelIndex &index) const;
    QModelIndex index(int row, int column,const QModelIndex &parent = QModelIndex()) const;
    int rowCount(const QModelIndex &parent) const;
    int columnCount(const QModelIndex &parent = QModelIndex()) const;
    QVariant data(const QModelIndex &index, int role) const;


    QVariant headerData(int section, Qt::Orientation orientation,int role = Qt::DisplayRole) const;

};


class MainWindow : public QMainWindow
{
    Q_OBJECT
    
public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
    


    QTreeView * view;
    MyTreeModel *model;


private:
    Ui::MainWindow *ui;
    QVBoxLayout * layout;
};

#endif // MAINWINDOW_H

The source file:

//mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QMessageBox>




QModelIndex MyTreeModel::parent(const QModelIndex &index) const
{
    return QModelIndex();
}

QVariant MyTreeModel::data(const QModelIndex &index, int role) const
{
    return "111";
}

QVariant MyTreeModel::headerData(int section, Qt::Orientation orientation,
                               int role) const
{
    if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
    {
        if(section==0)
            return "Column0";
        else if(section==1)
            return "Column1";
        else if(section==2)
            return "Column2";
        else
            return QVariant();
    }
    else
        return QVariant();
}

QModelIndex MyTreeModel::index(int row, int column, const QModelIndex &parent)
            const
{

    return createIndex(row, column, NULL);

}

int MyTreeModel::columnCount(const QModelIndex &parent) const
{
    return 3;
}

int MyTreeModel::rowCount(const QModelIndex &parent) const
{
    return 2;
}

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    model=new MyTreeModel();
    view= new QTreeView(this);
    view->setModel(model);

    layout= new QVBoxLayout(this);
    layout->addWidget(view);
    QWidget *window = new QWidget();
    window->setLayout(layout);
    setCentralWidget(window);
}

MainWindow::~MainWindow()
{
    delete ui;
}

I expect it will show a 2 rows * 3 columns of "111", but it does not. It only shows the header. If I change QVariant MyTreeModel::headerData to:

QVariant MyTreeModel::headerData(int section, Qt::Orientation orientation,
                               int role) const
{

        if(section==0)
            return "Column0";
        else if(section==1)
            return "Column1";
        else if(section==2)
            return "Column2";
        else
            return QVariant();

}

It will show nothing. The header also disappears.

Why?


Solution

  • Your code a has a couple of issues. Firstly, because it's a single level model the index, rowCount and columnCount members should only return 'real' values when the specified parent index is invalid (i.e. the nominal root index). So those members become...

    QModelIndex MyTreeModel::index (int row, int column, const QModelIndex &parent) const
    {
      if (parent.isValid())
        return {};
      return createIndex(row, column, nullptr);
    }
    
    int MyTreeModel::columnCount (const QModelIndex &parent) const
    {
      if (parent.isValid())
        return 0;
      return 3;
    }
    
    int MyTreeModel::rowCount (const QModelIndex &parent) const
    {
      if (parent.isValid())
        return 0;
      return 2;
    }
    

    Secondly, your MyTreeModel::data member always returns (effectively) QString("111"). That will fail for those roles where a QString can't be converted to the expected type: e.g. QSize for Qt::SizeHintRole. So the data member becomes...

    QVariant MyTreeModel::data(const QModelIndex &index, int role) const
    {
      if (role != Qt::DisplayRole)
        return {};
      return "111";
    }
    

    With the above changes the code appears to work as expected.