13.2.3 派生新模型类(5)
为了及时显示这些自发发生变化的节点,我们扩展了13.2.3节2. 中的代码,得到代码段13 6。模型类TreeModel的构造函数创建了一个QTimer对象,每秒发出一个timeout()信号,触发该类的槽函数timerHit()。在这个槽函数中,行①后的代码更新二叉树节点中的值,行②后的代码创建这些节点的索引,行③后的代码触发dataChanged()信号,通知视图类重新显示这些节点的值。
代码段13 6,显示自身发生变化的数据项,取自z:\examples\mvc\binary_tree_changing_data\treemodel.cpp
- TreeModel::TreeModel()
- {
- ……
- timer = new QTimer(this);
- timer->setInterval(1000);
- connect(timer, SIGNAL(timeout()) , this, SLOT(timerHit()));
- timer->start();
- }
- void TreeModel::timerHit()
- {
- numbers[14] = ( numbers[14] + 1 ) % 60; ①
- numbers[6] = numbers[14]+ numbers[13];
- numbers[2] = numbers[6] + numbers[5];
- numbers[0] = numbers[2] + numbers[1];
- QModelIndex idx_14= createIndex(1,0,14); ②
- QModelIndex idx_6 = createIndex(1,0,6);
- QModelIndex idx_2 = createIndex(1,0,2);
- QModelIndex idx_0 = createIndex(0,0,0);
- emit dataChanged(idx_14, idx_14); ③
- emit dataChanged(idx_6, idx_6 );
- emit dataChanged(idx_2, idx_2 );
- emit dataChanged(idx_0, idx_0 );
- }
5.更改标头
模型类的不可见根可能具有多行、多列子节点,其中每行、每列都具有一个标头(header)。当模型类中的数据项太多时,视图类无法在一个窗口显示出所有数据项,用户需要使用视图类提供的水平或者垂直滚动条进行察看。视图类会在每行左侧、每列顶部显示该行或者该列的标头,以使用户了解窗口所显示的数据属于哪行、哪列。默认情况下,模型类把每行的行号加1,作为该行的标头,把每列的列号加1,作为该列的标头。之所以加1,是由于模型类的行号或者列号始于0,而用户习惯从1开始对行或列进行编号。有的情况下,我们希望将标头设置为一些容易记忆、容易理解的字符串。
例如,满二叉树的例子中,模型类TreeModel的不可见根只有1个子节点(即二叉树的根节点),所以默认情况下,水平方向上只含有唯一的标头"1",如图13 12所示。我们希望将其更改为更容易理解的字符串"Full Binary Tree"。这可以通过重载QAbstractItemModel的虚函数headerData()来实现,如代码段13 7所示。
|
| 图13 12 更改标头 |
视图类在显示标头之前,会调用模型类的这个headerData()函数,向模型类查询每个标头对应的文字。函数参数orientation表示查询的是水平方向还是垂直方向的标头。当为水平方向时,section表示列号,当为垂直方向时,section表示行号。对于本例,我们仅设置水平方向第0列的标头为"Full Binary Tree"。对于其他情形,比如垂直方向第0行,该函数返回一个表示无效取值的QVariant对象,导致视图类在对应的位置不显示任何标头。
代码段13 7,更改数据集的标头,取自z:\examples\mvc\binary_tree_header\treemodel.cpp
- QVariant TreeModel::headerData(int section, Qt::Orientation orientation, int role) const
- {
- if (role == Qt::DisplayRole && section==0
- && orientation == Qt::Horizontal )
- return QString("Full Binary Tree");
- return QVariant();
- }