dbanet
dbanet

Reputation: 695

Qt Model-View programming. QAbstractItemModel and QAbstractListModel. index() and parent()

Please help me I'm stuck.

I've got a QList of structures I display in a specific format in a QTreeView. I've actually got not problem with displaying; I've reimplemented data() and it works just well.

My data is "flat", i. e. every node is a root element. Also the data doesn't need to be modified from the view, i. e. it's read-only.

The thing I don't get is what are model indexes. What is the proper use of them.

Currently in data() I return the corresponding item of a QList by the model row (index.row()). It seems to be legit, and that's what data() is for.

Apart of data() I've reimplemented rowCount(), columnCount(), flags() and headerData().

It is enough for a QAbstractListModel, but to subclass from QAbstractItemModel, I need also to reimplement parent() and index(). And I have no idea what exactly I need to do in these functions. If I return an empty model index (return QModelIndex()), I get no data displayed.

I understand the idea of MVC: the view is able to show the data in many ways that are most appropriate and useful. For example, the view may sort the data alphabetically, or anything, so the order of the rows displayed will differ from the way the data is organized in the application's internals. But I don't understand how would that work in my case, the case of my application and Qt.

The view just simply queries my model's data() function for each row and each column, and because the data I have doesn't get modified, e. g. sorted, the view always displays the data in the same order (even if I click the header to sort the view). I can sort the list myself, but then I will lose the right order (for example, the app wants to get an item #3, but after the list had been sorted, the needed item has got another number), and that doesn't look like MVC at all: when the View of the Data changes, the Data changes too. It shouldn't.

The above was the question. Here comes code.

Well, I thought there isn't much need for a code to illustrate my question as I already wrote enough words. I've actually got two problems: I'm currently subclassed from QAbstractListModel, but I want to subclass from QAbstractItemModel. So I need to write index() and parent(). Also I don't understand how sorting should work.

Anyway I've suddenly googled this page. It looks very close to what do I have (apart of editing: I don't need to edit my data with the view, so I didn't implement the corresponding functions; I also display pictures, not text only (no problem)). I would like to know how can I do the same (look at that page) with QAbstractItemModel.

If I'm unclear please let me know. :/

Upvotes: 3

Views: 3917

Answers (2)

dbanet
dbanet

Reputation: 695

@pavel-strakhov:

In the index() method you should return createIndex(row, column) if row and column are valid, and QModelIndex() otherwise. You can attach additional data to an index using the 3rd argument of createIndex.

This is totally wrong. I've implemented index() like I've been told in the above answer, and got a tree with infinite recursion: each node was having the whole tree in its children.

I don't even need to check if the row and column is valid, the view does it itself utilizing the model's rowCount() and columnCount() methods reasonably well.

Right way to do it:

QModelIndex HostModel::index(int row,int column,const QModelIndex &parent) const{
    if(!parent.isValid()) // we should return a valid QModelIndex for root elements (whose parent
        return this->createIndex(row,column); // is invalid) only, because our model is flat
    else
        return QModelIndex();
}

I was also asking if everything else I do with ModelIndexes is okay. No one has answered (even the author of the answer with 2 upvotes) me. No idea why. And why a wrong answer has gotten 2 upvotes I neither have an idea. You guys make it worse.

I think it's okay what I did in data(). But I'm not sure, however it works well now.

With the QSortFilterProxyModel() that proxies requests to my model (which corresponds to MVC) sorting now works okay (well, works great).

P. S. Huge thanks to @Lol4t0 for the help: he has told me privately on Skype how should I implement index().

Upvotes: 1

Pavel Strakhov
Pavel Strakhov

Reputation: 40512

Generally, if QAbstractListModel or QAbstractTableModel is suitable for your task, you should use it instead of QAbstractItemModel. You didn't say why exactly you want to derive from QAbstractItemModel.

But your question still can be answered:

  1. Since your data is flat, you should always return QModelIndex() in the parent() method.

  2. In the index() method you should return createIndex(row, column) if row and column are valid, and QModelIndex() otherwise. You can attach additional data to an index using the 3rd argument of createIndex.

Sorting is another question. Qt advises to separate data model logic and sorting logic. You should have a basic model with your main data. This model should be completely unaware of any sorting. You should use QSortFilterProxyModel object as the view's model, and use QSortFilterProxyModel::setSourceModel to set data source model for the sort model. The proxy model will do all sorting work, you just need to tell it what to do.

Upvotes: 3

Related Questions