13.2.3 派生新模型类(2)
依据这些公式,我们可以轻易地推出以下结论:
(1)所有左子节点的下标为奇数,所有右子节点的下标为偶数。
(2)模型类以若干行、若干列的形式存放一个父节点的子节点。对于二叉树,模型类会先存放其左子节点,再存放其右子节点。因而左子节点对应的行号为0,右子节点对应的行号为1。给定一个节点的数组下标i,该节点对应的行号为 (i+1) % 2。
我们从QAbstractItemModel派生一个模型类TreeModel表示这棵满二叉树,该类的声明如代码段13 1所示。满二叉树将被存放在该类的成员数组numbers中。类QAbstractItem Model具有多个虚函数,而TreeModel仅仅重载了其中5个必须重载的纯虚函数。
|
| 图13 10 使用数组存放一棵满二叉树 |
代码段13 1,类TreeModel的声明,取自z:\examples\mvc\binary_tree\treemodel.h
- class TreeModel : public QAbstractItemModel
- {
- Q_OBJECT
- public:
- TreeModel();
- int rowCount ( const QModelIndex & parent ) const;
- int columnCount ( const QModelIndex & parent ) const;
- QModelIndex index ( int row, int column, const QModelIndex & parent = QModelIndex() ) const;
- QModelIndex parent ( const QModelIndex & index ) const;
- QVariant data ( const QModelIndex & index, int role ) const;
- private:
- enum {N=15};
- int numbers[N];
- };
类TreeModel的实现如代码段13 2与代码段13 3所示。其构造函数将图13 10中的满二叉树存放在成员数组numbers中。一般情况下,模型类中的某个父节点可以包含若干行、若干列子节点,但是对于本例的满二叉树,一个父节点最多只含有2行、1列子节点。因而,成员函数columnCount()总是返回1。成员函数rowCount()应该返回一个父节点所含子节点的个数。当父节点的索引是一个无效索引时,表示该父节点是模型类的不可见根节点;函数返回1,表示该节点只含有一个子节点,也就是满二叉树的根节点。如果该父节点是满二叉树的非叶节点,函数返回2,表示非叶节点总是含有2个子节点。否则,该父节点是一个叶子节点,不含任何子节点,函数返回0。
代码段13 2,类TreeModel的实现,取自z:\examples\mvc\binary_tree\treemodel.cpp
- TreeModel::TreeModel()
- {
- int values[N]={36,10,26,3,7, 11,15, 1,2,3,4,5,6,7,8};
- for (int i=0; i<N; i++)
- numbers[i] = values[i];
- }
- int TreeModel::rowCount ( const QModelIndex & parent ) const
- {
- if ( ! parent.isValid() )
- return 1;
- if (parent.internalId() < N/2 )
- return 2;
- return 0;
- }
- int TreeModel::columnCount ( const QModelIndex & parent ) const
- {
- return 1;
- }
成员函数index()返回一个数据项的索引。参数parent是该数据项父节点的索引。其父节点可能含有多个子节点,参数row和column表示该子数据项所在的行号、列号。该函数调用QAbstractItemModel的成员函数createIndex()创建一个QModexIndex对象作为这个子数据项的索引。createIndex()函数的原型如下。
- QModelIndex QAbstractItemModel::createIndex ( int row, int column, void * ptr = 0 ) const
- QModelIndex QAbstractItemModel::createIndex ( int row, int column, quint32 id ) const