转载:落叶知秋时数据结构
类QabstractItemModel,QabstractListModel,QAbstractTableModel不保存数据,用户须要从这些类派生出子类,并在子类中定义某种数据结构来保存数据。app
与此不一样,类QStandardItemModel负责保存数据,每一个数据项被表示为类QStandardItem的对象。接下来,咱们主要从两个方面介绍类QStandardItemMode的内容。函数
首先来看第一方面:性能
如前文所述,一个数据项由若干个『角色,数据子项』对组成。类QStandardItem负责保存、访问这些数据。该类的内部定义了一个类型为QVector的容器,字体
每一个容器元素本质上存放一个『角色,数据子项』对。因为各个角色对应的数据子项可能具备不一样的类型,Qt使用QVariant来存放每一个数据子项。ui
当用户但愿将一些数据存放在一个QStandardItem对象中时,能够调用其成员函数:spa
void setData ( const QVariant & value, int role) //将『role, value』对存入。
当用户但愿读取该对象中的数据时,能够调用另一个成员函数:.net
QVariant data ( int role = ) const //读取角色role对应的数据子项。
以上两个函数是QStandardItem的核心。有了这两个函数,咱们就能够访问该类所表示数据项的任何一个『角色,数据子项』对。然而,对于一些经常使用角色,指针
该类提供了更加简洁、容易记忆的成员函数。例如,当一个数据项被显示在视图中时,它每每包含一些文字、一个图标,还可能包含一个复选框。code
经常使用角色:
该类提供的一组成员函数能够方便地访问这些经常使用角色对应的数据子项:
而后再来看第二方面:
类QStandardItemModel将类QStandardItem表示的数据项组织起来,造成列表、表格、树甚至更复杂的数据结构。
1:若是数据集被表示为一个列表,咱们能够调用类QStandardItemModel的成员函数appendRow()向列表中添加一个数据项,使用item()读取一个数据项。
如代码段13-10所示。
行②的构造函数在内部调用该类的setData()函数,将行②的QString对象做为Qt::DisplayRole对应的数据子项存入新构造的对象。
因为数据集自己是一个列表,因此咱们使用QListView显示该数据集,读者能够运行该例子查看显示结果。
代码段13-10:使用QStandardItemModel处理列表
QStandardItemModel listModel; QStandardItem *rootItem = listModel.invisibleRootItem(); // 行1 for (int row = 0; row < 4; ++row){
QStandardItem *item = new QStandardItem(QString("%1").arg(row) ); // 行2 rootItem->appendRow( item ); //行3 } QListView listView; listView.setModel ( & listModel );
2:若是数据集被表示为一个表格,能够调用类QStandardItemModel的成员函数setItem()设定表格中的某个数据项,如代码段13-11所示。
因为这个代码段中的数据集是一个表格,因此使用QTableView显示该数据集。
代码段13-11:使用QStandardItemModel处理表格
QStandardItemModel tableModel(4, 4); for (int row = 0; row < 4; ++row){ for (int column = 0; column < 4; ++column) { QStandardItem *item = new QStandardItem(QString("%0,%1").arg(row).arg(column)); tableModel.setItem(row, column, item); } } QTableView tableView; tableView.setModel( & tableModel );
3:若是数据集被表示为一个树,能够调用类QStandardItemModel的成员函数appendRow()向某个树节点添加子节点。
经过屡次调用该函数,能够构建一棵复杂的树。代码段13-12构建一棵简单的树:最顶层的根节点有一个文字内容为“0”的子节点,
该子节点有一个文字内容为“1”的子节点。依此类推,“1”子节点有一个“2”子节点,“2”子节点有一个“3”子节点,造成一棵深度为4的树。
这棵树的每一个节点都没有兄弟节点(具备相同父节点的多个节点被相互称为兄弟节点),感兴趣的读者能够修改这段代码,以使其中某些节点具备兄弟节点。
因为数据集是一棵树,咱们使用QTreeView显示它。
代码段13-12,使用QStandardItemModel处理树:
QStandardItemModel treeModel; QStandardItem *parentItem = treeModel.invisibleRootItem(); for (int i = 0; i < 4; ++i) { QStandardItem *item = new QStandardItem(QString("%0").arg(i)); parentItem->appendRow(item); parentItem = item; } QTreeView treeView; treeView.setModel( & treeModel );
类QStandardItemModel之因此可以表示列表、表格、树甚至更复杂的数据结构,得益于类QStandardItem在其内部定义了一个类型为
QVector<QStandardItem*>的容器,能够将每一个容器元素所指的QStandardItem对象设定为子对象。表如今如图13-13所示的类图上,类QStandardItem和自身具备“children”关系。一个类和自身发生关联,在UML中被称为自关联(self association)。类QStandardItemModel定义了一个名为root的数据成员,逻辑上是一个指向QStandardItem对象的指针。这个对象能够设定多个QStandardItem的对象做为本身的子对象,而其中每一个子对象又能够包含其余的子对象。依此类推,这棵树能够具备任意深度,每一个父对象能够包含任意多个子对象。
很天然地,QStandardItemModel可使用QStandardItem表示具备树状数据结构的数据集,如图13-14所示。
图中的每一个小方框表示类QStandardItem的一个对象。若是小方框的边线为虚,相应的QStandardItem对象并不表示数据集中的任何数据,仅被用来表示某种数据结构。若是小方框的边线为实,相应的QStandardItem对象就表示数据集中的一个数据项。在右侧的图中,QStandardItemModel的数据成员root所指的对象表示一个不可见的根,而数据集的根(图中结点G)被表示为这个不可见根的一个子节点。
列表被看做一个特殊的树:不可见根具备若干个子节点,每一个子节点表示列表中的一个数据项,再也不包含任何子节点,如该图左侧所示。
而表格的表示方式反而麻烦一些。不可见根含有若干子节点(图中A,B,C),这些子节点并不表示数据集中的任何数据项。
第i个子节点会包含若干子节点(好比图中D,E,F),这些子节点才表示表格第i行的数据项。
最后再讨论一下QStandardItemModel表示数据集的优缺点:
使用QStandardItemModel表示数据集具备如下优势:
然而,这种表示方法也有局限性:
好比,设数据集是一个1万行、20列的表格,其中第10列存放的是浮点数。若是咱们想计算这一列的平均值,按照图13-14,这须要遍历全部行,
取得第10列的QStandardItem对象,再依据角色“Qt::DisplayRole”取得对应的数据子项。因为这个数据子项的类型为QString,还须要将其转换为浮点数,
最后求全部浮点数的平均值。这些操做会耗费较长的时间。
所以,对于数据量不是很大、对性能要求不是很高的场合,咱们可使用类QStandardItemModel来表示一个数据集。
不然,用户应该从QAbstractItemModel、QAbstractListModel或者QAbstractTableModel派生新类,自行管理数据集的存放与访问。