PDA

View Full Version : How to store data in a tablemodel



rubikon
9th August 2012, 08:25
Hello.

I'm new to model view programming but I've successfully implemented a model inherited from QAbstractListModel:



class PaletteListModel : public QAbstractListModel
{
Q_OBJECT

public:
explicit PaletteListModel(QList<QColor> colors, QObject *parent);
int rowCount(const QModelIndex &parent = QModelIndex()) const;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
...
...
...
private:
QList<QColor> m_colors;

};

PaletteListModel::PaletteListModel(QList<QColor> colors, QObject *parent) :
QAbstractListModel(parent)
{
m_colors = colors;
}

int PaletteListModel::rowCount(const QModelIndex & ) const
{
return m_colors.count();
}
...
...


So I can pass a list which can have a dynamic length to the constructor which will be stored in a private field. With this I can determine the row count...

But how can I pass and store the data for a table model? I guess it has to be some kind of nested list. But I can't figure out how exactly to do this:



class PaletteTableModel : public QAbstractTableModel
{
Q_OBJECT

public:
explicit PaletteTableModel(??????? colors, QObject *parent);
int rowCount(const QModelIndex &parent = QModelIndex()) const;
int columnCount(const QModelIndex &parent = QModelIndex())) const;

private:
???????? m_colors;

};


PaletteTableModel::PaletteTableModel(??????? colors, QObject *parent) :
QAbstractTableModel(parent)
{
m_colors = colors;
}

int PaletteTableModel::rowCount(const QModelIndex & ) const
{
return ?????
}

int PaletteTableModel::columnCount(const QModelIndex &) const
{
return ?????
}
...
...
...

How do I have to implement this?

spirit
9th August 2012, 08:48
Not sure what you need. Can you clarify your thoughts?

rubikon
9th August 2012, 10:02
I want to have a model which stores a table of colors.

So basically: What do I have to write for the question marks in the second Qt Code of my first post?

spirit
9th August 2012, 10:06
Well, you already have the list of private colors -- it is the storage of the model.
You need to implement QAbstractItemModel::data (to display your colors), QAbstractItemModel::setData (to change existing colors), QAbstractItemModel::insertRows (to insert new colors), QAbstractItemModel::removeRows (to remove colors).

This is good stuff for reading (http://qt-project.org/doc/qt-4.8/model-view-programming.html#model-subclassing-reference).

rubikon
9th August 2012, 10:27
Well, you already have the list of private colors -- it is the storage of the model.

As I have written, implementing a list works fine. Now I want to implement a table not a list.

And I don't know how to store and pass the the two dimensional data through the constructor. For the one dimensional data I used QList<QColor> as I have written in the first Qt Code of my first posting.

But what 'datatype' or 'datastructure' do I have to use for an two dimensional data? Marked with question marks in the second Qt Code of my first post.




You need to implement QAbstractItemModel::data (to display your colors), QAbstractItemModel::setData (to change existing colors), QAbstractItemModel::insertRows (to insert new colors), QAbstractItemModel::removeRows (to remove colors).

This is good stuff for reading (http://qt-project.org/doc/qt-4.8/model-view-programming.html#model-subclassing-reference).

I'm aware of that and already know how to do that. What I don't know is how to pass two dimensional data through the constructor, store the two dimensional data and determine the range of my two dimensional data in rowCount(const QModelIndex & ) and columnCount(const QModelIndex &) const.

spirit
9th August 2012, 10:33
Okay, got it.
Yes, you should use nested lists or vectors in this case.

rubikon
9th August 2012, 11:27
Okay, thank you. But how do I have to do it? Could you complete the second Qt code for my first post, so I can see how to do it?

spirit
9th August 2012, 12:31
class PaletteTableModel : public QAbstractTableModel
{
Q_OBJECT

public:
explicit PaletteTableModel(const QList<QList<QColor> > &colors, QObject *parent);
int rowCount(const QModelIndex &parent = QModelIndex()) const;
int columnCount(const QModelIndex &parent = QModelIndex())) const;

private:
QList<QList<QColor> > m_colors; //suppose the first list keeps rows, the second -- columns

};


PaletteTableModel::PaletteTableModel(const QList<QList<QColor> > &colors, QObject *parent) :
QAbstractTableModel(parent), m_colors(colors)
{

}

int PaletteTableModel::rowCount(const QModelIndex &) const
{
return m_colors.count();
}

int PaletteTableModel::columnCount(const QModelIndex &index) const
{
//TODO: add an index checks and boundary checks
return m_colors.at(index.row()).count();
}
...
...
...

rubikon
13th August 2012, 13:21
Thank you for your completion. I have tried to complete the code:



PaletteTableModel::PaletteTableModel(QList< QList<QColor> > colors, QObject *parent) :
QAbstractTableModel(parent)
{
m_colors = colors;
}

int PaletteTableModel::rowCount(const QModelIndex & ) const
{
return m_colors.count();
}

int PaletteTableModel::columnCount(const QModelIndex &index) const
{
return m_colors.at(index.row()).count();
}


For the first try I passed an empty list to the constructor:



private:
PaletteTableModel *m_model;
QList< QList<QColor> > m_list;

...
...

m_model = new PaletteTableModel(m_list, this);
ui->tableView->setModel(m_model);


But setModel fails with

---------------------------
Microsoft Visual C++ Runtime Library
---------------------------
This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.
---------------------------
OK
---------------------------


Where is the problem?

spirit
13th August 2012, 13:25
I think the problem is here


int PaletteTableModel::columnCount(const QModelIndex &index) const
{
return m_colors.at(index.row()).count();
}

You are not checking the index. That leads to error in QList::at -- wrong range.
I specially added TODO in this method definition.

rubikon
13th August 2012, 14:15
I'm not able to implement a check...

The first thing I've tried is this


int PaletteTableModel::columnCount(const QModelIndex &index) const
{
if(index.row() > (m_colors.count() - 1))
return 0;

if(index.column() > (m_colors.at(index.row()).count()) - 1)
return 0;

return m_colors.at(index.row()).count();
}


But the function is getting called with index.row() = -1. Why gets the function called with index.row() = -1?
So I extended the function

int PaletteTableModel::columnCount(const QModelIndex &index) const
{
if(index.row() < 0)
return 0;

if(index.row() > (m_colors.count() - 1))
return 0;

if(index.column() > (m_colors.at(index.row()).count()) - 1)
return 0;

return m_colors.at(index.row()).count();
}

Now it works with an empty list.
But when I try to fill the two dimensional list and pass it like this


QList<QColor> list;

list << QColor(Qt::red) << QColor(Qt::green) << QColor(Qt::blue);
m_list << list << list << list;

m_model = new PaletteTableModel(m_list, this);

I still get the same error. What am I doing wrong?

spirit
13th August 2012, 14:18
But the function is getting called with index.row() = -1. Why gets the function called with index.row() = -1?
I still get the same error. What am I doing wrong?

Because an index can be invalid see QModelIndex::isValid.
So, you should at first check the index validity


...
if (!index.isValid())
return 0;
...