13.2.3 派生新模型类(4)
代码段13 5,能够处理更多角色的模型类,取自z:\examples\mvc\binary_tree_more_role\treemodel.cpp
- QVariant TreeModel::data ( const QModelIndex & index, int role ) const
- {
- switch (role) {
- case Qt::DisplayRole:{
- int value = numbers[ index.internalId() ];
- return QVariant( value );
- }
- case Qt::ForegroundRole: ①
- if ( index.internalId() >= N/2 ) ②
- return QBrush(Qt::red);
- break;
- case Qt::FontRole: ③
- QFont font;
- if ( index.internalId() >= N/2 )
- font.setPointSize(26);
- else
- font.setPointSize(20);
- return font;
- }
- return QVariant(); ④
- }
4.数据变化时通知视图类
数据集中的数据项可能自发地发生变化。例如,当一个应用程序从网络上下载文件时,数据集中的某个数据项被用来表示已经下载的字节数。每当一些字节被成功下载,这个数据项会被更新。如果某个视图类负责显示这个数据项,模型类应该通知该视图类这个变化,以使视图类更新这个数据项的显示。
模型类使用Qt的信号与槽机制通知视图类。每当模型类中的某个或者某些数据项发生变化时,模型类发出一个dataChanged()信号,该信号的函数参数表明了哪些数据项发生了变化,其原型为:
- void QAbstractItemModel::dataChanged ( const QModelIndex & topLeft,
- const QModelIndex & bottomRight )
当只有一个数据项发生变更时,上述两个函数参数都指向这个数据项。当有多个数据项发生变化,而且这些数据项具有相同的父节点时,topLeft是最左上角那个数据项的索引,而bottomRight是最右下角那个数据项的索引。例如,当数据集是一个表格时,所有数据项都具有一个共同的父节点(即模型类的不可见根节点)。如果按照从上到下、从左到右的顺序看,有多个连续的数据项发生了变化,函数参数topLeft以及bottomRight可以表示哪些数据项发生了变化。
当我们调用某个视图类的setModel()函数,令其显示一个模型类中的数据集时,该函数会将dataChanged()信号与视图类中的某个槽函数绑定。一旦模型类发出dataChanged()信号,视图类中的槽函数就会被调用,该槽函数就会查询topLeft与bottomRight之间数据项的取值,并重新显示这些数据项。
如果一个父节点下的多个不连续的子节点发生变化,模型类应该将这些子节点分为多个小的区域,其中每个区域中的子节点是连续的。然后,发出多个dataChanged()信号,每个信号只涉及其中一个小区域中的子节点。如果发生变化的节点根本不属于同一个父节点,模型类必须发出多个dataChanged()信号,其中每个信号所涉及的节点必须具有相同的父节点。
为了模拟"数据项自发地发生变化"的情形,我们令图13 11中二叉树的最后一个节点(含有数字"8"的那个)每1秒钟增加1,增加到60时归零,也就是令这个节点表示当前时间的秒数部分。我们还有意地令这个问题更加复杂:当这个节点发生变化时,从这个节点到二叉树根的所有节点都应该被更新,以满足"父节点中的数字等于子节点中的数字之和"这个规则。也就是说,图中含有数字"15"、"26"、"36"的节点都应该被更新。
|
| (点击查看大图)图13 11 二叉树的部分节点自发发生变化 |