文章目录
QAbstractItemModel 类
QAbstractItemModel类为项目模型类提供了抽象接口。
Header: | #include < QAbstractItemModel > |
---|---|
qmake: | QT += core |
Inherits: | QObject |
Inherited By: | QAbstractListModel, QAbstractProxyModel, QAbstractTableModel, QConcatenateTablesProxyModel, QDirModel, QFileSystemModel, and QStandardItemModel |
详述
QAbstractItemModel类定义了一个标准接口,项目模型必须使用这个接口才能与模型/视图体系结构中的其他组件进行互操作。它不应该被直接实例化。相反,您应该子类化它来创建新的模型。
QAbstractItemModel类是模型/视图类之一,是Qt的模型/视图框架的一部分。它可以用作QML中的项视图元素或Qt Widgets模块中的项视图类的基础数据模型。
如果您需要一个模型与项目视图一起使用,比如QML的列表视图元素或c++小部件QListView或QTableView,那么您应该考虑使用QAbstractListModel或QAbstractTableModel子类来代替这个类。
底层数据模型使用具有层次结构的表格形式交给视图和委托。如果不使用层次结构,那么模型就是一个简单的行和列的表格。每个项都有一个由QModelIndex指定的惟一索引。
可以通过模型访问的每个数据项都有一个关联的模型索引。您可以使用index()函数获得这个模型索引。每个索引可以有一个sibling() 索引;子项有一个parent() 索引。
每个项都有许多与之关联的数据元素,可以通过为模型的data()函数指定一个角色(参见Qt::ItemDataRole)来检索它们。可以使用itemData()函数同时获得所有可用角色的数据。
注:每个数据项都是一堆数据,放置于数据项的不同角色下,还包括各种属性:是否可以被选择、拖动等。
每个角色的数据是使用特定的Qt::ItemDataRole设置的。单个角色的数据可以使用setData()单独设置,也可以使用setItemData()为所有角色设置。
可以使用flags() 函数(参见Qt::ItemFlag)查询项目,看看它们是否可以被选择、拖动或以其他方式操纵。
如果一个项有子对象,则hasChildren()返回对应索引的true。
对于层次结构的每一层,模型都有一个rowCount()和一个columnCount()。可以使用insertRows()、insertColumns()、removeRows()和removeColumns()插入和删除行和列。
模型发出信号来指示更改。例如,每当模型可用的数据项发生更改时,就会发出dataChanged()。对模型提供的头的更改将导致发出headerDataChanged()。如果底层数据的结构发生了变化,模型可以发出layoutChanged(),以指示附加的视图应该重新显示显示的任何项,同时考虑到新结构。
可以使用match()函数搜索模型中可用的项以查找特定数据。
要对模型进行排序,可以使用sort()。
子类化
注意:在模型子类化参考中有一些关于模型子类化的一般指南(见:Model Subclassing Reference)。
在子类化QAbstractItemModel时,至少必须实现index()、parent()、rowCount()、columnCount()和data()。这些函数在所有只读模型中使用,并构成可编辑模型的基础。
您还可以重新实现hasChildren() ,以为rowCount() 的实现成本很高的模型提供特殊的行为。 这使得模型可以限制视图请求的数据量,并且可以用作实现模型数据的惰性填充的一种方式。
要在模型中启用编辑功能,还必须实现setData()和重新实现 flags(),以确保返回 ItemIsEditable 。您还可以重新实现headerData()和setHeaderData()来控制模型头部的呈现方式。
在重新实现setData()和setHeaderData()函数时,必须显式地分别发出dataChanged()和headerDataChanged()信号。
自定义模型需要为其他组件创建模型索引。为此,使用项目合适的行号和列号以及它的标识符(作为指针或整数值)调用createIndex()。对于每个项,这些值的组合必须是惟一的。自定义模型通常在其他重新实现的函数中使用这些惟一标识符来检索项数据和访问关于项的父项和子项的信息。有关惟一标识符的更多信息,请参见简单树模型示例(Simple Tree Model Example)。
不需要支持Qt::ItemDataRole中定义的每个角色。根据模型中包含的数据类型,可能只有实现data()函数才能为一些更常见的角色返回有效信息。大多数模型至少为Qt::DisplayRole提供项目数据的文本表示,而且行为良好的模型还应该为Qt::ToolTipRole和Qt::WhatsThisRole提供有效的信息。支持这些角色使模型能够与标准Qt视图一起使用。但是,对于一些处理高度专门化数据的模型,可能适合仅为用户定义的角色提供数据。
模型为了调整数据结构的大小提供了相关的接口:insertRows()、removeRows()、insertColumns()和removeColumns()的实现。当实现这些功能时,在模型维度发生变化之前和之后通知所有连接视图是很重要的:
- insertRows()实现必须在将新行插入数据结构之前调用beginInsertRows(),然后立即调用endInsertRows()。
- insertColumns()实现必须在将新列插入数据结构之前调用beginInsertColumns(),然后立即调用endInsertColumns()。
- removeRows()实现必须在从数据结构中删除行之前调用beginRemoveRows(),然后立即调用endRemoveRows()。
- removeColumns()实现必须在列从数据结构中删除之前调用beginRemoveColumns(),然后立即调用endRemoveColumns()。
这些函数发出的私有信号使附加组件有机会在任何数据变得不可用之前采取行动。使用这些begin和end函数封装插入和删除操作还使模型能够正确地管理持久模型索引。如果希望正确处理选择,则必须确保调用了这些函数。如果插入或移除带有子项的项,则不需要为子项调用这些函数。换句话说,父项将照顾其子项。
要创建增量填充的模型,可以重新实现fetchMore()和canFetchMore()。如果fetchMore()的重新实现向模型中添加了行,则必须调用beginInsertRows()和endInsertRows()。
参见Model Classes, Model Subclassing Reference, QModelIndex, QAbstractItemView, Using drag and drop with item views, Simple DOM Model Example, Simple Tree Model Example, Editable Tree Model Example, and Fetch More Example 获取更多示例。
公共类型
enum class CheckIndexOption
flags CheckIndexOptions
用来控制QAbstractItemModel::checkIndex()执行的检查。
Constant | Value | Description |
---|---|---|
CheckIndexOption::NoOption | 0x0000 | 没有指定检查选项。 |
CheckIndexOption::IndexIsValid | 0x0001 | 传递给QAbstractItemModel::checkIndex()的模型索引被检查为有效的模型索引。 |
CheckIndexOption::DoNotUseParent | 0x0002 | 不执行任何涉及到传递给QAbstractItemModel::checkIndex()的父索引的使用的检查。 |
CheckIndexOption::ParentIsInvalid | 0x0004 | 传递给QAbstractItemModel::checkIndex()的模型索引的父索引被检查为无效的模型索引。如果同时指定了此选项和DoNotUseParent,则忽略此选项。 |
enum LayoutChangeHint
模型改变布局的方式
Constant | Value | Description |
---|---|---|
NoLayoutChangeHint | 0 | No hint is available. |
VerticalSortHint | 1 | Rows are being sorted. |
HorizontalSortHint | 2 | Columns are being sorted. |
注意,VerticalSortHint和HorizontalSortHint表示项目在同一父级中移动,而不是移动到模型中的不同父级,也没有过滤掉或过滤进来。
公共函数
构造析构
- QAbstractItemModel(QObject *parent = nullptr)
- virtual ~QAbstractItemModel()
角色和标志
- virtual QHash<int, QByteArray> roleNames() const
- virtual Qt::ItemFlags flags(const QModelIndex &index) const
行列
- virtual int columnCount(const QModelIndex &parent = QModelIndex()) const = 0
- virtual int rowCount(const QModelIndex &parent = QModelIndex()) const = 0
索引
- virtual QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const = 0
- bool checkIndex(const QModelIndex &index, QAbstractItemModel::CheckIndexOptions options = CheckIndexOption::NoOption) const
- bool hasIndex(int row, int column, const QModelIndex &parent = QModelIndex()) const
- virtual QModelIndex buddy(const QModelIndex &index) const 返回index的好友项的索引
- virtual QModelIndex sibling(int row, int column, const QModelIndex &index) const
- virtual QModelIndex parent(const QModelIndex &index) const = 0
- virtual bool hasChildren(const QModelIndex &parent = QModelIndex()) const
- virtual bool canFetchMore(const QModelIndex &parent) const
- virtual void fetchMore(const QModelIndex &parent)
表头
- virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const
- virtual bool setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role = Qt::EditRole)
项数据
- virtual QMap<int, QVariant> itemData(const QModelIndex &index) const
- virtual bool setItemData(const QModelIndex &index, const QMap<int, QVariant> &roles)
- virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const = 0
- virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole)
查找、排序、占用空间
- virtual QModelIndexList match(const QModelIndex &start, int role, const QVariant &value, int hits = 1, Qt::MatchFlags flags = Qt::MatchFlags(Qt::MatchStartsWith|Qt::MatchWrap)) const
- virtual void sort(int column, Qt::SortOrder order = Qt::AscendingOrder)
- virtual QSize span(const QModelIndex &index) const
插入、删除、移动行和列
- bool insertColumn(int column, const QModelIndex &parent = QModelIndex())
- virtual bool insertColumns(int column, int count, const QModelIndex &parent = QModelIndex())
- bool insertRow(int row, const QModelIndex &parent = QModelIndex())
- virtual bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex())
- bool removeColumn(int column, const QModelIndex &parent = QModelIndex())
- virtual bool removeColumns(int column, int count, const QModelIndex &parent = QModelIndex())
- bool removeRow(int row, const QModelIndex &parent = QModelIndex())
- virtual bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex())
- bool moveColumn(const QModelIndex &sourceParent, int sourceColumn, const QModelIndex &destinationParent, int destinationChild)
- virtual bool moveColumns(const QModelIndex &sourceParent, int sourceColumn, int count, const QModelIndex &destinationParent, int destinationChild)
- bool moveRow(const QModelIndex &sourceParent, int sourceRow, const QModelIndex &destinationParent, int destinationChild)
- virtual bool moveRows(const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destinationParent, int destinationChild)
拖放
- virtual Qt::DropActions supportedDragActions() const
- virtual Qt::DropActions supportedDropActions() const
- virtual bool canDropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) const
- virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent)
- virtual QMimeData * mimeData(const QModelIndexList &indexes) const
- virtual QStringList mimeTypes() const
公共槽
- virtual void revert() 让模型丢弃缓存的信息,这个函数通常用于row 的编辑。
- virtual bool submit() 让模型知道它应该将缓存的信息提交到永久存储。
信号
基本都是行列或者项目变化的信号
- void columnsAboutToBeInserted(const QModelIndex &parent, int first, int last)
- void columnsAboutToBeMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationColumn)
- void columnsAboutToBeRemoved(const QModelIndex &parent, int first, int last)
- void columnsInserted(const QModelIndex &parent, int first, int last)
- void columnsMoved(const QModelIndex &parent, int start, int end, const QModelIndex &destination, int column)
- void columnsRemoved(const QModelIndex &parent, int first, int last)
- void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector &roles = QVector< int >())
- void headerDataChanged(Qt::Orientation orientation, int first, int last)
- void layoutAboutToBeChanged(const QList< QPersistentModelIndex> &parents = QList< QPersistentModelIndex>(), QAbstractItemModel::LayoutChangeHint hint = QAbstractItemModel::NoLayoutChangeHint)
- void layoutChanged(const QList< QPersistentModelIndex> &parents = QList< QPersistentModelIndex>(), QAbstractItemModel::LayoutChangeHint hint = QAbstractItemModel::NoLayoutChangeHint)
- void modelAboutToBeReset()
- void modelReset()
- void rowsAboutToBeInserted(const QModelIndex &parent, int start, int end)
- void rowsAboutToBeMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationRow)
- void rowsAboutToBeRemoved(const QModelIndex &parent, int first, int last)
- void rowsInserted(const QModelIndex &parent, int first, int last)
- void rowsMoved(const QModelIndex &parent, int start, int end, const QModelIndex &destination, int row)
- void rowsRemoved(const QModelIndex &parent, int first, int last)
受保护的函数
-
void beginInsertColumns(const QModelIndex &parent, int first, int last) 开始一个列插入操作
在子类中重新实现insertColumns()时,必须在将数据插入模型的底层数据存储之前调用此函数。
父索引对应于插入新列的父索引;第一个和最后一个是新列插入后的列号。
指定要插入到模型项中的列的范围的第一个和最后一个列号。
例如,如图所示,我们在列4之前插入了三列,所以首先是4,最后是6:beginInsertColumns(parent, 4, 6);
最终插入的三个新列作为列4、5和6。
要追加列,请将它们插入到最后一列之后。
例如,如图所示,我们将三列附加到现有六列的集合中(以列5结束),所以第一个是6,最后一个是8:beginInsertColumns(parent, 6, 8);
最终追加两个新列作为列6、7和8。
注意:这个函数发出columnsAboutToBeInserted()信号,在插入数据之前连接的视图(或代理)必须处理哪个视图。否则,视图可能会以无效状态结束。
-
void beginInsertRows(const QModelIndex &parent, int first, int last) 开始行插入操作
-
bool beginMoveColumns(const QModelIndex &sourceParent, int sourceFirst, int sourceLast, const QModelIndex &destinationParent, int destinationChild) 开始一个列移动操作
-
bool beginMoveRows(const QModelIndex &sourceParent, int sourceFirst, int sourceLast, const QModelIndex &destinationParent, int destinationChild) 开始行移动操作
当重新实现子类时,此方法简化了模型中实体的移动。此方法负责在模型中移动持久索引,否则您将需要自己执行此操作。使用beginMoveRows和endMoveRows可以替代直接发送layoutAboutToBeChanged和layoutChanged以及changePersistentIndex。源目录索引对应于行被移动的父索引;sourceFirst和sourceLast是要移动的行的第一个和最后一个行号。destinationParent索引对应于将这些行移动到其中的父索引。destinationChild是将行移动到的行。也就是说,sourceParent中行sourceFirst处的索引将成为destinationParent中的行destinationChild,后面跟着到sourceLast的所有其他行。
但是,当在同一父目录下移动行(sourceParent和destinationParent是相等的)时,这些行将被放置在destinationChild索引之前。也就是说,如果您希望移动0和1行,使它们变成1和2行,destinationChild应该是3。在本例中,源行i(位于sourceFirst和sourceLast之间)的新索引等于(destinationChild-sourceLast-1+i)。
注意,如果sourceParent和destinationParent是相同的,您必须确保destinationChild不在sourceFirst和sourceLast + 1的范围内。您还必须确保不会尝试将一行移动到它自己的子行或祖先行中。如果任一条件为真,此方法将返回false,在这种情况下,应中止移动操作。
指定源父行中您希望在模型中移动的行跨度的第一行和最后一行编号。还要指定要将span移动到的目标父对象中的行。例如,如图所示,我们在源代码中从第2行移动了3行到第4行,因此sourceFirst是2,sourceLast是4。我们将这些项移动到目的地的第2行上面,因此destinationChild是2。
beginMoveRows(sourceParent, 2,4, destinationParent, 2); 这将把源中的3行第2、第3和第4行移动到目标中的2、第3和第4行。其他受影响的兄弟姐妹因此而流离失所。若要将行追加到另一个父元素,请将它们移到最后一行的后面。例如,如图所示,我们将三行移动到现有的6行集合中(以第5行结束),因此destinationChild为6:beginMoveRows(sourceParent, 2,4, destinationParent, 6);这将目标行移动到目标父行6、7和8的末尾。 若要在同一父目录中移动行,请指定要移动它们的行。例如,如图所示,我们将一项从第2行移动到第0行,因此sourceFirst和sourceLast为2,destinationChild为0。 beginMoveRows(parent, 2, 2, parent, 0); 注意,其他行可能相应地被置换。还请注意,在移动同一父元素中的项时,不应尝试无效或无操作的移动。在上面的例子中,item 2在移动之前的第2行,因此不能移动到第2行(它已经在那里)或第3行(no-op,因为第3行表示在第3行之上,它已经在那里) 若要在同一父目录中移动行,请指定要移动它们的行。例如,如图所示,我们将一项从第2行移动到第4行,因此sourceFirst和sourceLast为2,destinationChild为4。 beginMoveRows(parent, 2, 2, parent, 4); 注意,其他行可能相应地被置换。 -
void beginRemoveColumns(const QModelIndex &parent, int first, int last)
-
void beginRemoveRows(const QModelIndex &parent, int first, int last)
-
void beginResetModel()
-
void endInsertColumns()
-
void endInsertRows()
-
void endMoveColumns()
-
void endMoveRows()
-
void endRemoveColumns()
-
void endRemoveRows()
-
void endResetModel()
-
QModelIndexList persistentIndexList() const
-
void changePersistentIndex(const QModelIndex &from, const QModelIndex &to)
-
void changePersistentIndexList(const QModelIndexList &from, const QModelIndexList &to)
-
QModelIndex createIndex(int row, int column, void *ptr = nullptr) const
-
QModelIndex createIndex(int row, int column, quintptr id) const
受保护的槽
-
void resetInternalData()
这个插槽在模型的内部数据被清除并被重置之后被调用。这个插槽为具体代理模型的子类提供了便利,例如QSortFilterProxyModel的子类维护了额外的数据。
总结
QAbstractItemModel 类 应该是设计模式中的模板,定义了各种接口,其它类继承这个类,并实现自己的特有功能。