PDA

View Full Version : Source code for createIndex() ?



neuronet
26th December 2014, 19:32
I am learning to code in PySide (Qt in Python), and find it helpful to look at the C++ source code for things when I am confused.

I am having trouble finding the implementation of createIndex(), which we use for QAbstractItemModel. It is a method under QtCore.QAbstractItemModel, so I expect to find it in qabstractitemmodel.cpp. Indeed I see the documentation therein (https://qt.gitorious.org/qt/qt/source/acc9bc4d9dd3b7a1fef10fe88bfa753e515cdd3e:src/corelib/kernel/qabstractitemmodel.cpp#L1980), but not the actual code that implements it.

So, where is QAbstractItemModel::createIndex()? I'm not a C++ programmer, so assume I'm missing something obvious. :o

ars
26th December 2014, 20:04
Hello,

I looked into Qt 4.7.3 sources and there createIndex() is defined as an inline method in the header file under src/corelib/kernel/qabstractitemmodel.h. I assume this did not change in more recent versions (Qt 5.x).

Best regards
ars

neuronet
26th December 2014, 20:25
Hello,

I looked into Qt 4.7.3 sources and there createIndex() is defined as an inline method in the header file under src/corelib/kernel/qabstractitemmodel.h. I assume this did not change in more recent versions (Qt 5.x).


You are right, got it thanks. Here it is: (https://qt.gitorious.org/qt/qt/source/57756e72adf2081137b97f0e689dd16c770d10b1:src/corelib/kernel/qabstractitemmodel.h#L319)

inline QModelIndex QAbstractItemModel::createIndex(int arow, int acolumn, void *adata) const
{ return QModelIndex(arow, acolumn, adata, this); }
And then I wonder what this QModelIndex function is, and it is defined in the same file:

inline QModelIndex() : r(-1), c(-1), p(0), m(0) {}
inline QModelIndex(const QModelIndex &other)
: r(other.r), c(other.c), p(other.p), m(other.m) {}
And I don't really understand what it is doing (can anywone explain? (e.g., p(other.p)--what is that?) ).

Perhaps I should have been more clear about my goal: I am asking because the implementation of index within QAbstractTableModel is:

QModelIndex QAbstractTableModel::index(int row, int column, const QModelIndex &parent) const
{
return hasIndex(row, column, parent) ? createIndex(row, column, 0) : QModelIndex();
}
And I am confused about the third input to createIndex: why is it just 0 when the corresponding item has an index? Why doesn't it return the data item using something like an internalPointer? That is, I am used to sending an actual data item as the third input to createIndex (as in the simpletreemodel example that comes with Qt). (In C++ I think you send a pointer as the third item, but even so why send the integer 0?).

ars
26th December 2014, 21:30
inline QModelIndex() : r(-1), c(-1), p(0), m(0) {}
This is the default constructor for a QModelIndex creating an invalid index. The implementation initializes internal members r, c, p and m to the values shown in () above.

inline QModelIndex(const QModelIndex &other)
: r(other.r), c(other.c), p(other.p), m(other.m) {}
This is the copy constructor creating a new QModelIndex as a copy of the existing QModelIndex other. The new index gets initialized with the internal state of the other object.

In
QModelIndex QAbstractTableModel::index(int row, int column, const QModelIndex &parent) const
{
return hasIndex(row, column, parent) ? createIndex(row, column, 0) : QModelIndex();
}
method
createIndex(int, int, int) gets called with 3rd parameter set to 0. In the implementation of this method you will find a reinterpret_cast of the 3rd parameter to void pointer. From my understanding you need the 3rd parameter to create tree like structures (or even more sophisticated data structures). For plain tables I've never needed the 3rd createIndex() parameter.

Best regards
ars

neuronet
26th December 2014, 23:02
ars: your post helps, but I am still confused. I think what I'll do is think about it more, and probably make it into a separate post, as you have already answered my original question about where the source code is, which was the point of this thread :)

I'm thinking for the next question it will be more about how to understand what the hell is going on with createIndex, expecially in Python which has no pointers.

I have actually asked about this, tangentially, here, but never really understood what was going on...
http://www.qtcentre.org/threads/59747-Is-third-input-to-createIndex-really-a-pointer

anda_skoa
27th December 2014, 11:59
From my understanding you need the 3rd parameter to create tree like structures (or even more sophisticated data structures). For plain tables I've never needed the 3rd createIndex() parameter.

The third parameter can be used by a model as an additional reference when row and column are not enough. Which indeed is usually only required for trees.
But a model is free to use that even for tables or lists, e.g. store the pointer to the row or cell right in the index.

Cheers,
_

d_stranz
28th December 2014, 00:20
The third parameter is also defined as a void * pointer, which in reality means it can contain anything that will fit into the size of a pointer (usually the same size as an unsigned long). In Python, you could possibly use this to store the index into a list of objects, for example. The implementation of PySide might even coerce a Python object reference into a pointer "under the hood" so you may be able to store a Python object reference in it.

But as anda_skoa says, it is rare that you need to use this third parameter unless you are implementing a tree or a proxy model where it would be difficult to navigate the model otherwise.

neuronet
30th December 2014, 03:12
The third parameter is also defined as a void * pointer, which in reality means it can contain anything that will fit into the size of a pointer (usually the same size as an unsigned long). In Python, you could possibly use this to store the index into a list of objects, for example. The implementation of PySide might even coerce a Python object reference into a pointer "under the hood" so you may be able to store a Python object reference in it.

But as anda_skoa says, it is rare that you need to use this third parameter unless you are implementing a tree or a proxy model where it would be difficult to navigate the model otherwise.

Very useful stuff. I am indeed building a tree model by subclassing QAbstractItemModel. I was looking at the implementation of QAbstractTableModel just to check that I understood what I was doing.

Indeed, in Python, the third input to createIndex is actually just any old Python object, of any type. Typically we just feed in the data item itself to become referred to by the index (e.g., in simpletreemodel example, we give it a TreeItem type directly as the parameter, no pointers or anything like that, which don't exist in Python).

I have finally started to sort out these issues in a couple of threads over at stack overflow:
http://stackoverflow.com/questions/27613702/is-there-duplication-of-data-among-qt-model-items
http://stackoverflow.com/questions/27683764/what-is-a-pyobject-in-python

Though I a admit I am still a bit puzzled by the following:

inline QModelIndex(const QModelIndex &other)
: r(other.r), c(other.c), p(other.p), m(other.m) {}
As I said, I am no c++ coder, so this just seems foreign to me. It seems to be creating a QModelIndex out of these r (row), c (column), p (pointer to the data item), and m (I assume the model that it got the index from). But I don't where where it is creating the .row(), .column(), .getInternalPointer(), .model(), and other methods associated with an index. Where is that behavior defined? I can see how it would be fairly easy to get those methods based on the parameters the function is receiving, but would like to see in the source how it all works...

wysota
30th December 2014, 08:14
In C++ a method named the same as a class is called a constructor (similar to Python's __init__()). Fields of the class are defined elsewhere - statically in the class declaration as C++ is a strongly typed language which does not allow to add new members to objects during the life of the object. The constructor only initializes those fields with values which is what you can see in the snippet after the colon symbol. The constructor presented is called a copy constructor - it creates an instance from another instance of the same class.

neuronet
30th December 2014, 13:47
In C++ a method named the same as a class is called a constructor (similar to Python's __init__()). Fields of the class are defined elsewhere - statically in the class declaration as C++ is a strongly typed language which does not allow to add new members to objects during the life of the object. The constructor only initializes those fields with values which is what you can see in the snippet after the colon symbol. The constructor presented is called a copy constructor - it creates an instance from another instance of the same class.

That is really helpful stuff as I try to make sense of the source. And I missed the class declaration in the header file:
Direct link to class declaration of QModelIndex (https://qt.gitorious.org/qt/qt/source/57756e72adf2081137b97f0e689dd16c770d10b1:src/corelib/kernel/qabstractitemmodel.h#L58)