13.4 选择操作
视图类允许用户使用键盘或者鼠标选择某个或者某些数据项。视图类提供三种选择模式:
(1)单选模式。用户最多只能选择一个数据项。
(2)多选模式。用户可以选择多个数据项。图13 16显示了一个具有8行、4列的数据集。按照从上到下、从左到右的阅读顺序,某些被选中的数据项是相邻的,比如图中(2,2)到(3,3)之间的6个数据项,它们形成一个"选择块"。选择块可以包含多个数据项,也可以只包含一个数据项,比如图中的(8,4)。多选模式下,一个视图可能包含多个选择块,这些选择块互不相邻。
(3)扩展模式。一个视图只允许有一个选择块,用户只能在这个选择块的末尾选择新的数据项以扩展现有的选择块,不可以选择一个和当前选择块不相邻的数据项。
|
| 图13 16 多选模式与QItemSelectionRange的作用 |
Qt使用类QItemSelectionRange描述每个选择块,其数据成员tl是选择块中最左上角数据项的索引,br是最右下角数据项的索引。该类的成员函数indexes()返回该选择块中所有数据项的索引。如图13 17所示(是图13 5"Qt的Model/View框架"的一部分),数据成员tl、br的类型为QPersistentModelIndex,意味着即使相关的数据集发生了变化,比如其中部分数据项被删除或者新增添了数据项,tl、br仍然分别指向选择块的最左上角、最右下角数据项。
如果有多个QPersistentModelIndex类型的索引指向同一个数据集中的若干个数据项,每当这个数据集发生任何更改,就需要维护所有这些索引,代价较大。一般场合下,Model/View框架中的其他类并不需要使用这种类型的索引,类型为QModelIndex的索引就能够满足它们的要求。因此,类QPersistentModelIndex重载了一个类型转换运算符,将一个QPersistentModelIndex对象转换为一个QModelIndex对象。QItemSelectionRange的成员函数indexes()就调用了这个函数,以QList<QModelIndex>类型返回一个选择块中所有数据项的索引。
|
| 图13 17 Model/View框架中与数据项选择相关的类 |
类QItemSelection描述由多个选择块组成的一个集合。在多选模式下,用户最近一次选择的数据项信息被记录在一个QItemSelection对象中。这些信息被称为"当前选择"(current selection),类QItemSelectionModel使用一个名为"currentSelection"的指针指向这个对象。在最近一次选择操作之前,视图对象已有的选择信息也被表示为一个QItemSelection对象,这些信息被称为"已有选择",类QItemSelectionModel使用一个名为"ranges"的指针指向这个对象。
本书所讨论的Qt版本虽然在QItemSelectionModel的实现层面上做了"当前选择"与"已有选择"的划分,但是QItemSelectionModel并没有将这种划分呈现给使用该类的用户。例如,该类的公有成员函数selectedIndexes()合并这两个部分,将合并结果返回给调用者,调用者无法区分哪些数据项属于"当前选择",哪些数据项属于"已有选择"。
类QItemSelectionModel除了管理"当前选择"与"已有选择"之外,还负责监视选择信息的变更。一旦有变更,会触发诸如selectionChanged()这样的信号,通知视图对象及时更新显示。每个视图对象的内部定义了一个指针,指向一个QItemSelectionModel对象,以记录该视图所显示的数据项的选择状态信息。当多个视图对象显示同一个数据集中的数据项时,这些视图对象可以指向同一个QItemSelectionModel对象,使得用户在某个视图所做的选择操作会被立即同步到其他视图中。
类QItemSelectionModel并不处理与选择操作相关的键盘或者鼠标事件,这由视图对象负责。当用户执行了某些选择操作,比如用鼠标圈选了一些数据项,视图对象会判断这个操作涉及哪些数据项,然后通知该视图对象所指的QItemSelectionModel对象执行相应的选择(或者取消选择)操作。QItemSelectionModel对象更改这些数据项的选择状态,触发一个selectionChanged()信号,通知指向这个对象的所有视图对象更新显示。