QAbstractItemModel为item model类提供了抽象接口。
该类定义了item models必须使用的标准接口,使其能够在model/view架构中与其他组件进行交互。它不能直接实例化,但能子类化它来创建新的model。
QAbstractItemModel是一个model/view类,同时是qt model/view框架的一部分。它能在QML视图项元素或Qt Widgets模块中的视图项类中用作基本的数据模型。
如果你需要一个model,该model用于view的item。比如QML List View的元素或者C++ widgets的QListView,QTableView,此时你应该考虑子类化QAbstractListModel或QAbstractTableModel而不是该类。
底层的数据model作为表的层次结果暴露给视图和委托。如果你不使用此结构,该model是一个具有行和列的简单表。每一个item都有一个唯一的由QModelIndex指定的index。
每一个item项的数据有一个关联的model index,能通过model来访问数据。你能通过index()函数来获取model index。每一个index可能有sibling()索引(兄弟索引),子项有parent()索引。
每一个item有若干元素与之关联,并能通过特定的角色(见Qt::Item)检索到model的data()函数。可以使用itemData()函数同时获得所有可用角色的数据。
每个角色的数据通过使用特定的Qt::ItemDataRole来设定。个别角色的数据使用setData()单独设置,或使用setItemData()为所有role设定。
Items能够通过flags()函数(见 Qt::IemFlag)去查看是否它们能够被选择,拖动或其他方式的操作。
如果Item有子对象,对于对应index,hasChildren返回true。
对每个水平的层级,model有rowCount()和columncount()函数。使用insertRows(), insertColumns()插入行列,使用 removeRows(), removeColumns()移除行列。
Model通过发射信号指示改变。E.g 当模型可用的数据项被更改时,dataChanged()就会发出。更改由模型提供的头部导致headerDataChanged()信号发送。如果底层数据的结构发生变化,考虑新的结构,该模型发出layoutChanged()信号来指示任何与之附加的视图更新其所有显示的Item项。
通过model使用match函数能够检索特定的数据,items是可用的。可以使用sort函数来排序model。
QAbstractTableModel提供了一个抽象的模型,能够被子类化创建table模型。
QAbstractTableModel为model提供了一个标准的接口,能够以一个两维数组项表示他们的数据。不能直接使用,必须被子类化。
因为比QAbstractItemModel提供了更多具体的接口,并不适合tree视图的使用,尽管它也用于给QListView提供数据。如果你需要表示一个简单的关于items的列表,并仅需要一个包含单列数据的模型,子类化QAbstractListModel可能更合适。
rowCount() 和 columnCount()函数返回表的维度。要检索与模型中某个项相对应的模型索引,使用index()函数并提供行号和列号。
子类化
当子类化QAbstractTableModel时,必须实现rowCount(),columnCount,和data()函数。QAbstractTableModel提供index(),parent()函数的默认实现。表现良好的模型也应该实现headerData函数。
可编辑的模型需要实现setData()函数,并实现flags()函数返回包含Qt::ItemIsEditable的值。
模型提供可调整数据结构的接口,可以提供insertRows(),romoveRows(),insertColums,removeColumns的实现。当实现这些函数的时候,调用适当的函数是很重要的,这样所有连接的视图都能感知到模型的任何改变。
insertRows()的实现必须在插入新行到数据结构前调用beginInsertRows,随后必须调用endInsertRows()。
insertColumns()的实现必须在插入新列到数据结构前调用beginInsertColumns(),随后必须调用endInsertColumns()。
removeRows()的实现必须在行被移出数据结构前调用beginRemoveRows(),随后必须调用
endRemoveRows()。
removeColumns()的实现必须在列被移出数据结构前调用beginRemoveColumns(),随后必须调用endRemoveColumns()。
模型子类化需要实现很多定义在QAbstractItemModel中虚函数。这些需要被实现的函数的数量取决于模型的类型,它是否为视图提供了一个简单的列表,一个table,或一个复杂层次的items。继承QAbstractListModel 和 QAbstractTableModel的模型能够利用由这些基类提供的默认实现的优点。以树状结构显示项数据的模型必须提供很多QAbstractItemModel中虚函数实现。
子类模型中需要实现的函数可以划分为以下三组:
项数据处理
模型可以提供不同级别的访问数据:可以是简单的只读组件,一些模型可能支持调整大小的操作,而其他则可能允许编辑内容。
只读访问
为了提供对模型提供的数据的只读访问,必须在模型的子类中实现以下函数:
函数 | 功能 |
---|---|
flags() | 供其他组件使用以获取模型提供的每个项的信息。在许多模型中,falgs的组合应该包括Qt::ItemIsEnabled 和Qt:ItemIsSelectable。 |
data() | 用于向视图和委托提供项数据。通常,模型只需要为Qt::DisplayRole和任何特定应用程序的user roles提供数据.但是,为Qt::ToolTipRole, Qt::AccessibleTextRole, 和 Qt::AccessibleDescriptionRole提供数据也一个很好的做法。参阅Qt::ItemDataRole文档,以了解与每个角色相关的类型信息 |
headerData() | 提供用于显示头部的视图信息。该信息仅由视图检索并能够显示头部信息。 |
rowCount() | 提供由模型暴露的行数 |
这四个函数必须在所有类型的模型中实现,包括list模型(QAbstractListModel subclasses)和table模型(QAbstractTableModel subclasses)。
此外,以下函数必须在QAbstractTableModel 和 QAbstractItemModelr的直接子类中实现:
columnCount() | 提供由模型暴露的列数。List模型不用提供此函数,因为在QAbstractListModel中已经实现。 |
可编辑项
可编辑模型允许修改数据项,还可以提供允许插入和删除行列的函数。为了使能编辑,以下函数必须实现:
函数 | 功能 |
---|---|
flags() | 必须为每个项返回合适的falgs组合。特别地,在只读模型中,这个函数返回的值必须另外包含Qt::ItemIsEditable应用于项。 |
setData() | 用于修改与指定的模型索引相关的数据项。为了能够接受用户界面元素提供的用户输入,这个函数必须处理与Qt::EditRole相关的数据。该实现可以也接受由Qt::ItemDataRole指定的与不同类型roles相关的数据。在更改了数据项之后,模型必须发出dataChanged()信号,以通知其他组件的更改。 |
setHeaderData() | 用于修改水平和垂直头部信息。在更改了数据项之后,模型必须发出headerDataChanged()信号,以通知其他组件更改。 |
可调整大小的模型
所有类型的模型都可以支持插入和删除行。表模型和层次模型也可以支持插入和删除列。在改变之前和之后,通知其他组件关于模型的维度变化是很重要的。因此,以下函数可以实现允许模型重新调整,但是实现必须确保调用适当的函数来通知其附加的视图和委托:
insertRows()
用于向所有类型的模型添加新行和数据项。插入前调用beginInsertRows(),插入后调用endInsertRows() 。
removeRows()
用于从所有类型的模型中删除行和数据项。删除前调用
insertColumns()
同理
removeColumns()
同理
一般来说,如果操作成功,这些函数应该返回true。然而,有些情况下操作仅部分成功; 例如,如果插入的行数少于指定的行数。在这种情况下,模型应该返回false表明失败使任何与之附加组件能够处理这种情况。
在调整大小API的实现中由函数调用发射的信号给了附加组件一个机会在任何数据变为不可用之前采取行动。以begin和end函数插入和移除操作的封装也使模型能够正确地管理持久的model index。
通常,begin和end函数能够胜任通知其他组件关于model底层结构的改变。对于模型结构更复杂的改变,或许涉及内部数据的重组和排序,发射layoutChanged()信号引起任何附加视图的更新是有必要的。