QT6 源(122)模型视图架构, model - view结构里的模型总基类 QAbstractItemModel 篇二:给出源代码带注释

(3)本源代码的完善,是在学习了整个第五章以后,才完成的。确保新知识都由老师讲过了。而且,对本抽象基类的测试,也是通过其子类进行的。很分散。在列表模型,二维表模型,以及文件系统模型里。所以,这里就不再测试了。直接给出源码,定义于头文件 qabstractitemmodel . h

/*
#define Q_OBJECT \
public: \
    QT_WARNING_PUSH \
    Q_OBJECT_NO_OVERRIDE_WARNING \
    static const QMetaObject staticMetaObject; \
    virtual const QMetaObject *metaObject() const; \
    virtual void *qt_metacast(const char *); \
    virtual int qt_metacall(QMetaObject::Call, int, void **); \
    QT_TR_FUNCTIONS \
    private: \
    Q_OBJECT_NO_ATTRIBUTES_WARNING \
    Q_DECL_HIDDEN_STATIC_METACALL static void qt_static_metacall(QObject *, QMetaObject::Call, int, void **); \
    QT_WARNING_POP \
    struct QPrivateSignal {}; \
    QT_ANNOTATE_CLASS(qt_qobject, "")

*/

/*
The QAbstractItemModel class provides the abstract interface for item model classes.

Detailed Description :
QAbstractltemModel 类定义了项目模型必须使用的标准接口,以便能够与模型/视图体系结构中的其他组件进行互作。
它不应该直接实例化。相反,您应该将其子类化以创建新型。

QAbstractltemModel 类是Model/iew类之一,是Qt模型/视图框架的一部分。
它可以用作 QML中的项视图元素或 Qt Widgets模块中的项视图类的底层数据模型。

如果您需要与某个项目视图(如 QML的 List View元素或 C++中的 QListView或 QTableview)一起使用的模型,
应考虑继承自 QAbstractListModel或 QAbstractTableModel,而非接使用此类。

基础数据模型作为表的层次结构公开给视图和委托。如果不使用层次结构,那么模型就是一个由行和列组成的简单表。
每个项目都有一个由QModellndex指定的唯一索引。
The underlying data model is exposed to views and delegates as a hierarchy of tables.
If you do not make use of the hierarchy,
then the model is a simple table of rows and columns.
Each item has a unique index specified by a QModelIndex.

每个可通过模型访问的数据项都有一个关联的模型索引。
您可以使用`index()函数获取此模型索引。每个索引可能有一个兄弟索引;子项有一个父索引。
Every item of data that can be accessed via a model has an associated model index.
You can obtain this model index using the index() function.
Each index may have a sibling() index; child items have a parent() index.


每个项目都关联有多个数据元素,
可以通过向模型的data()函数指定一个角色(参见Qt:ItemDataRole)来检索这些数据元素。
同时,还可以使用itemData()函数获取所有可用角色的数据。
Each item has a number of data elements associated with it and they can be retrieved检索 by
    specifying a role (see Qt::ItemDataRole) to the model's data() function.
Data for all available roles can be obtained at the same time using the itemData() function.


每个角色的数据都使用特定的Qt::ItemDataRole进行设置。
单个角色的数据可以使用setData ()单独设置,也可以使用setItemData()为所有角色设置。
Data for each role is set using a particular Qt::ItemDataRole.
Data for individual roles are set individually with setData(),
     or they can be set for all roles with setItemData().

可以通过flags()(参见Qt::temFlag)查询项目是否可以被选择、拖动或以其他方式操作。
Items can be queried with flags() (see Qt::ItemFlag) to see if
    they can be selected, dragged, or manipulated in other ways.


如果一个项目有子对象,hasChildren()在相应索引处返回true。
If an item has child objects, hasChildren() returns true for the corresponding index.


该模型为每一层级提供了`rowCount()、和`columnCount()'方法。
可以使用`insertRows()、insertColumns()、`removeRows()、和`removeColumns()、来插入和删除行与列。
The model has a rowCount() and a columnCount() for each level of the hierarchy.
Rows and columns can be inserted and removed with insertRows(), insertColumns(),
                                                removeRows(), and removeColumns().


该模型会发出信号以指示变化。例如,每当模型提供的数据项发生更改时,就会发出`dataChanged ()'信号。
模型提供的头信息发生更改时,会发出`headerDataChanged ()'信号。
如果底层数据的结构发生变化,模型可以发出layoutChanged ()、信号,以便通知任何附加的视图,
它们应根据新的结构重新显示显示的任何项目。
The model emits signals to indicate changes.
For example, dataChanged() is emitted whenever
    items of data made available by the model are changed.
Changes to the headers supplied by the model cause headerDataChanged() to be emitted.
If the structure of the underlying data changes,
    the model can emit layoutChanged() to indicate to any attached views that
    they should redisplay any items shown, taking the new structure into account.


通过模型可用的项目可以通过match()函数搜索特定数据。The items available through the
model can be searched for particular data using the match() function.

要对模型进行排序,您可以使用sort()。

Subclassing :
注意:有关模型子类化的通用指南可在模型子类化参考中找到。Note: Some general guidelines for
subclassing models are available in the Model Subclassing Reference.

当子类化QAbstractItemModel时,至少必须实现index(),parent(),rowCount(),columnCount(和data()。
这些函数用于所有只读模型,并构成可编辑模型的基础。
When subclassing QAbstractItemModel, at the very least,
 you must implement index(), parent(), rowCount(), columnCount(), and data().
These functions are used in all read-only models, and form the basis of editable models.


您还可以重新实现`haschildren()'方法,以便为那些`rowCount()'实现较为昂贵的模型提供特殊行为。
这使得模型能够限制视图请求的数据量,并且可以作为实现模型数据懒加载的一种方式。
You can also reimplement hasChildren() to provide special behavior for models where the
implementation of rowCount() is expensive.
This makes it possible for models to restrict the amount of data requested by views,
and can be used as a way to implement lazy population of model data.


为了在模型中支持编辑功能,您还必须实现`setData ()'方法,
并重写`flags ()'方法以确保返回'ItemIsEditable。
此外,您还可以重写`headerData()`和`setHeaderData()、方法,以控制模型中标题的显示方式。
To enable editing in your model, you must also implement setData(),
and reimplement flags() to ensure that ItemIsEditable is returned.
You can also reimplement headerData() and setHeaderData() to control the
    way the headers for your model are presented.

在重实现`setData()和`setHeaderData()函数时,
必须明确发出`dataChanged() 和  headerDataChanged()'信号。
The dataChanged() and headerDataChanged() signals must be emitted explicitly when
    reimplementing the setData() and setHeaderData() functions, respectively.

自定义模型需要为其他组件创建模型索引。为此,请调用`createlndex()、函数,
传入与该项目对应的合适行号和列号,以及一个标识符,该标识符可以是一个指针或一个整数值。
这些值的组合必须对每个项目都是唯一的。
自定义模型通常在其他重写过的函数中使用这些唯一标识符来检索项目数据,并访问关于该项目父项和子项的信息。
有关唯一标识符的详细信息,请参“简单树模型示例”。
Custom models need to create model indexes for other components to use.
To do this, call createIndex() with suitable row and column numbers for the item,
    and an identifier for it, either as a pointer or as an integer value.
The combination of these values must be unique for each item.
Custom models typically use these unique identifiers in other reimplemented functions to
    retrieve item data and access information about the item's parents and children.
See the Simple Tree Model Example for more information about unique identifiers.

没有必要支持 Qt::ltemDataRole 中定义的所有角色。
根据模型所包含的数据类型,可能只需要实现 data() 函数,以便为某些较为常见的角色返回有效信息。
大多数模型至少会为 Qt:.DisplayRole 提供项目数据的文本表示,
而行为良好的模型还应会为 Qt:ToolTipRole 和 Qt::WhatsThisRole 提供有效信息。
支持这些角色使得模型能够与标准的 Qt 视图一起使用。
然而,对于一些处理高度专业化数据的模型,可能更合适仅向用户定义的权限提供数据。
It is not necessary to support every role defined in Qt::ItemDataRole.
Depending on the type of data contained within a model,
it may only be useful to implement the data() function to return
    valid information for some of the more common roles.
Most models provide at least a textual representation of item data for the Qt::DisplayRole,
and well-behaved models should also provide valid information for the
    Qt::ToolTipRole and Qt::WhatsThisRole.
Supporting these roles enables models to be used with standard Qt views.
However, for some models that handle highly-specialized data,
it may be appropriate to provide data only for user-defined roles.

提供可调整大小数据结构接口的模型,可以同时实现、insertRows()、removeRows、
insertcolumns(和`removeColumns ('等函数。
在实现这些函数时,重要的是要在操作前后通知所有连接的视图,告知模型尺寸发生了改变。
Models that provide interfaces to resizable data structures
    can provide implementations of insertRows(), removeRows(),
    insertColumns(),and removeColumns().
When implementing these functions,
it is important to notify any connected views about changes to the
    model's dimensions both before and after they occur:

*实现必须在将新行插入数据结构insertRows之前调用beginlnsertRows(),并在之后立即调用 endInsertRows().
An insertRows() implementation must call beginInsertRows() before inserting new rows
    into the data structure, and endInsertRows() immediately afterwards.

*实现必须在将新列插入数据结构InsertColumns之前调用 beginInsertColumns(),
并在之后立即调用endinsertColumns().
An insertColumns() implementation must call beginInsertColumns() before inserting
    new columns into the data structure, and endInsertColumns() immediately afterwards.

*A的`removeRows()`实现必须在从数据结构中移除行之前调用`beginRemoveRows()',
 并在之后立即调用endRemoveRowsA的'removeColumns.
A removeRows() implementation must call beginRemoveRows() before the
    rows are removed from the data structure, and endRemoveRows() immediately afterwards.

*(实现必须在从数据结构中移除列之前调用`beginRemoveColumns()、,并在之后立即调用endRemoveColumns.
A removeColumns() implementation must call beginRemoveColumns() before the
    columns are removed from the data structure,
    and endRemoveColumns() immediately afterwards.

这些函数发出的私有信号,为附加组件提供了在数据变得不可用时采取行动的机会。
通过将插入和删除操作封装在这些开始和结束函数中,还使得模型能够正确管理持久的模型索引。
如果您希望对选择进行处理,则必须确保调用这些函数。
如果插入或删除带有子项的项,则无需为子项调用这些函数。换言之父项将负责处理其子项。
The private signals that these functions emit give attached components the
    chance to take action before any data becomes unavailable.
The encapsulation of the insert and remove operations with these begin and end functions
    also enables the model to manage persistent model indexes correctly.
If you want selections to be handled properly,
 you must ensure that you call these functions.
If you insert or remove an item with children,
you do not need to call these functions for the child items.
In other words, the parent item will take care of its child items.

要创建增量填充的模型,您可以重新实现 fetchMore()和canFetchMore()。
如果fetchMore()的重新实现向模型添加了行,则必须调用beginInsertRows()和endInsertRows()。
To create models that populate incrementally,
 you can reimplement fetchMore() and canFetchMore().
If the reimplementation of fetchMore() adds rows to the model,
beginInsertRows() and endInsertRows() must be called.

*/

class Q_CORE_EXPORT QAbstractItemModel : public QObject
{
    Q_OBJECT  //插入此宏,以表示使用 Qt 的元对象系统

    friend class QPersistentModelIndexData; //声明三个友元类
    friend class QAbstractItemViewPrivate;
    friend class QAbstractProxyModel;

private:
    Q_DECLARE_PRIVATE(QAbstractItemModel)

    Q_DISABLE_COPY(QAbstractItemModel)

protected:    //保护权限,只由子类和自己访问的有参构造函数
    QAbstractItemModel(QAbstractItemModelPrivate  & dd, QObject * parent = nullptr);

    //Creates a model index for the given row and column with the internal pointer ptr.
    //When using a QSortFilterProxyModel, its indexes have their own internal pointer.
    //It is not advisable to access this internal pointer outside of the model.
    //  Use the data() function instead.
    //This function provides a consistent interface that
    //  model subclasses must use to create model indexes.   //创建 ptr 表格里的索引
    inline QModelIndex createIndex(int row, int column, const void * ptr = nullptr) const
    { return QModelIndex(row, column, ptr, this); }

    inline QModelIndex createIndex(int row, int column, quintptr id) const
    { return QModelIndex(row, column, id , this); }          //模型创建自己的索引
    //Creates a model index for the given row and column with the internal identifier, id.

public:
    //Constructs an abstract item model with the given parent.
    explicit QAbstractItemModel(QObject * parent = nullptr); //有参构造函数

    virtual ~QAbstractItemModel(); //虚析构函数

    //Returns the index of the item in the model specified by the given row,
    //  column and parent index.
    Q_INVOKABLE virtual
    QModelIndex   index(int row, int column, //模型由本函数返回程序员需要的条目索引
                        const QModelIndex & parent = QModelIndex()) const = 0;

    //经测试,结论为: 若参数 parent[row, column]合理,本模型可以为此处的条目创建索引,才返回true。
    Q_INVOKABLE    //否则返回 false。
    bool       hasIndex(int row, int column,
                        const QModelIndex & parent = QModelIndex()) const;
    //Returns true if the model returns a valid QModelIndex
    //  for row and column with parent, otherwise returns false.

    //此枚举可用于控制QAbstractItemModel::checkIndex()执行的检查。
    enum class CheckIndexOption {
        NoOption         = 0x0000,  //No check options are specified.
        IndexIsValid     = 0x0001,  //传递给的模型索引 checkindex()是检查为有效的模型索引。
        DoNotUseParent   = 0x0002,  //不执行任何涉及传递给 checkindex()中索引的父级索引的使用检查。
        ParentIsInvalid  = 0x0004,  //checkIndex()中形参索引的父索引被检查为无效的模型索引。
                                    //如果同时指定了此选项和DoNotUseParent,则忽略此选项。
    };
    Q_ENUM(CheckIndexOption)
    Q_DECLARE_FLAGS(CheckIndexOptions, CheckIndexOption)

    [[nodiscard]]                   //总之,本函数用于自定义模型,所以意义不大。
    bool     checkIndex(const QModelIndex & index,
                        CheckIndexOptions options = CheckIndexOption::NoOption) const;
    //这个函数检查形参索引是否是该模型的一个合法模型索引。
    //合法模型索引要么是一个无效的模型索引 QModelIndex(),要么是一个满足以下所有条件的有效模型索引:
    //索引的模型是这样的; the index' model is this;
    //索引的行大于或等于零;
    //索引的行数小于索引父项的行数;
    //索引列大于或等于零;
    //索引列小于索引父项的列数。
    //选项参数可能会改变其中一些检查。如果选项包含IndexIsValid,那么索引必须是一个有效的索引;
    //  这在重新实现诸如 data()或 setData()这样的函数时非常有用,因为这些函数期望有效的索引。
    //如果选项包含“DoNotUseParent”,那么将调用父类的那些检查将被省略;
    //  这允许从父类的重实现中调用此函数(否则将导致无休止的递归并导致崩溃)。
    //如果选项中不包含“DoNotUseParent”,且包含“ParentIsInvalid”,则会执行额外的检查:
    //  检查父索引是否有效。这在实现扁平模型如列表或表格)时非常有用,
    //  在这些模型中,任何模型索引都不应具有有效的父索引。
    //该函数如果所有检查都成功,则返回true,否则返回false。
    //这使得该函数可以在 Q_ASSERT 以及其他类似的调试机制中使用。
    //如果某些检查失败,将在qt.core.qabstractitemmodel.checkindex 日志类别中打印警告消息,
    //  其中包含一些可能有助于调试故障的信息。
    //注意: 此函数是用于实现您自己的item 模型的调试助手。
    //在开发复杂模型以及构建复杂的模型层次结构(例如使用代理模型)时,调用此函数非常有用,
    //  以便捕获与意外传递给某些OAbstractltemModelAPI的非法模型索引(如上定义)相关的错误。
    //警告:请注意,将非法索引传递给项模型属于未定义行为,因此应用程序应避免这样做,
    //  也不应依赖项模型可能采用的“防御性”编程方式来优雅地处理非法索引。


    using QObject::parent;  //QObject * QObject::parent() const 返回本对象的容器父类

    //返回具有给定索引的模型项的父级。如果该项没有父级,则返回无效的QModellndex。
    //在用于展示树状数据结构的模型中,一种常用的约定是,只有第一列中的项才有子项。
    //在这种情况下,当在子类中重写此函数时,返回的 QModellndex的列数将为 0。
    //当在子类中重新实现此函数时,需格外小心,避免调用 QModellndex成员函数,如 QModellndex::parent(),
    //因为属于您模型的索引只会调用您的实现,从而导致无限递归。
    //注意:此函数可以通过元对象系统和QML调用。参见 QINVOKABLE。 //这里构成了函数重载。
    Q_INVOKABLE virtual QModelIndex parent(const QModelIndex & child) const = 0;
    //注意:此求模型里条目的父条目的索引的成员函数,在列表与表格子模型里是private 权限禁用的。


    //Returns the sibling at row and column for the item at index,
    //  or an invalid QModelIndex if there is no sibling at that location.
    //sibling() is just a convenience function that finds the item's parent,这句很奇怪。
    // and uses it to retrieve the index of the child item in the specified row and column.
    //返回与形参 3的索引在同一父类下的位于 (row, column) 坐标处的同伴的索引。故形参 3不可为空。
    Q_INVOKABLE virtual
    QModelIndex sibling(int row, int column, const QModelIndex & idx) const;


    //Returns a model index for the buddy of the item represented by index.
    //When the user wants to edit an item, the view will call this function to
    //  check whether another item in the model should be edited instead.
    //Then, the view will construct a delegate using the model index returned by the
    //  buddy item.
    //The default implementation of this function has each item as its own buddy.
    //返回与索引 index 所代表的项相关的伙伴项的模型索引。
    //当用户想要编辑一项内容时,视图会调用此函数,以检查是否应同时编辑模型中的另一项内容。
    //随后,视图会使用伙伴项返回的模型索引来构建一个委托对象。
    //此函数的默认实现将每个项目作为自己的伙伴。 //总结:用代理修改条目时会用到本函数。
    virtual QModelIndex buddy(const QModelIndex & index) const;
    //伙伴buddy。sibling:指有血缘或法律关系的兄弟姐妹。
    //buddy:通常指朋友、伙伴或同事,强调亲密或友好的关系,无血缘关联。

    //Returns the number of rows under the given parent.
    //返回给定父节点下的行数。当父节点有效时,表示rowcount正在返回父节点的子节点数量。
    //注意:在实现基于表格的模型时,当父对象有效时,rowCount()应返回0。----->????
    Q_INVOKABLE virtual
    int       rowCount(const QModelIndex & parent = QModelIndex()) const = 0;

    Q_INVOKABLE virtual
    int    columnCount(const QModelIndex & parent = QModelIndex()) const = 0;
    //Returns the number of columns for the children of the given parent.
    //In most subclasses, the number of columns is independent of the parent.
    //Note: When implementing a table based model,
    //  columnCount() should return 0 when the parent is valid.

    Q_INVOKABLE virtual //判断某节点下面是否含有条目,即该节点是父节点 ?????随后测试
    bool hasChildren(const QModelIndex & parent = QModelIndex()) const;
    //Returns true if parent has any children; otherwise returns false.
    //Use rowCount() on the parent to find out the number of children.
    //Note that it is undefined behavior to report that
    //  a particular index hasChildren with this method if the
    //  same index has the flag Qt::ItemNeverHasChildren set.
    //若形参节点具有 Qt::ItemNeverHasChildren 属性,则再调用本函数是无效的。

//*********************************************************************************
//**********因访问模型里的条目必须经过索引,故先学习索引的建立与查询************************
//*********************************************************************************

    //Returns the item flags for the given index. //默认允许条目 enabled与可被选择。
    //The base class implementation returns a combination of flags that enables the
    //  item (ItemIsEnabled) and allows it to be selected (ItemIsSelectable).
    Q_INVOKABLE virtual Qt::ItemFlags flags(const QModelIndex & index) const;

    virtual QSize span(const QModelIndex & index) const;
    //Returns the row and column span of the item represented by index.
    //Note: Currently, span is not used.

    //Returns the data stored under the given role for the item referred to by the index.
    Q_INVOKABLE virtual  //对于可编辑的子类模型,必须重新实现本函数与 setData()函数。
    QVariant   data(const QModelIndex & index, int role = Qt::DisplayRole) const = 0;

    Q_INVOKABLE virtual  //把索引 index指向的条目的 role角色的数据设置为 value。
    bool    setData(const QModelIndex & index, //本函数会触发 dataChanged()信号的发射。
                    const QVariant    & value, int role = Qt::EditRole);
    //Sets the role data for the item at index to value.
    //Returns true if successful; otherwise returns false.
    //The dataChanged() signal should be emitted if the data was successfully set.
    //The base class implementation returns false.
    //This function and data() must be reimplemented for editable models.

    virtual //Fills the roleDataSpan with the requested data for the given index.
    void  multiData(const QModelIndex & index, QModelRoleDataSpan roleDataSpan) const;
    //整个调用中的索引是相同的。
    //这意味着,为了获取索引所需的信息,可以只进行一次数据结构的访问将相关代码从循环中提取出来)。
    //建议使用`QModelRoleData::setData()'或类似的`QVariant::setValue ()'函数,
    //而不是单独构造一·QVariant`对象并使用简单的赋值运算符,
    //这是因为前者允许重复利用为存储在`QModelRoleData`中对象已分配的内存,
    //而后者则总是为新变体分配内存,然后销毁旧变体。的QVariant`
    //请注意,视图可能会使用先前调用中使用的范围调用`multiData()、因此其中可能已经包含一些数据。
    //因此,如果模型无法为给定的角色返回数据,那么它必须清除相应`QModelRoleData`对象中的数据。
    //可以通过调用`QModelRoleData::clearData(),
    //或者通过设置一个默认构造的`QVariant'等方式来完成此操作。
    //未能清除数据将导致视图认为应使用“旧”数据来处理相应角色。
    //Note: Models are not allowed to modify the roles in the span,
    //  or to rearrange the span elements. Doing so results in undefined behavior.
    //Note: It is illegal to pass an invalid model index to this function.



    //Returns a map with values for all predefined roles in the model for the
    //  item at the given index.
    //Reimplement this function if you want to extend the
    //  default behavior of this function to include custom roles in the map.
    virtual   //返回 Qt 里条目里的所有预定义角色的数据,组成键值对返回。
    QMap<int, QVariant>    itemData(const QModelIndex & index) const;

    virtual   //为索引 index指向的条目设置角色数据。
    bool                setItemData(const QModelIndex & index,
                                    const QMap<int, QVariant> & roles);
    //Sets the role data for the item at index to the associated value in roles,
    //  for every Qt::ItemDataRole.
    //Returns true if successful; otherwise returns false.
    //Roles that are not in roles will not be modified.

    virtual   //删除本索引指向的条目里的所有数据。
    bool              clearItemData(const QModelIndex & index);
    //Removes the data stored in all the roles for the given index.
    //Returns true if successful; otherwise returns false. //本函也会触发 dataChanged()信号
    //The dataChanged() signal should be emitted if the data was successfully removed.
    //The base class implementation returns false。

    //Returns the data for the given role and section in the header with the
    //  specified orientation. For horizontal headers,
    //the section number corresponds to the column number.
    //Similarly, for vertical headers, the section number corresponds to the row number.
    Q_INVOKABLE 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 QStringList mimeTypes() const;

    virtual            //typedef QList<QModelIndex> QModelIndexList;
    QMimeData *        mimeData(const QModelIndexList & indexes) const;

    virtual
    bool           dropMimeData(const QMimeData * data, Qt::DropAction action,
                                int row, int column, const QModelIndex & parent);

    virtual
    bool        canDropMimeData(const QMimeData * data, Qt::DropAction action,
                                int row, int column, const QModelIndex & parent) const;

    //Returns true if there is more data available for parent; otherwise returns false.
    //The default implementation always returns false.
    //If canFetchMore() returns true, the fetchMore() function should be called.
    //This is the behavior of QAbstractItemView, for example.
    Q_INVOKABLE virtual  //查看 parent 的子表里是否还有条目可便利。????
    bool        canFetchMore(const QModelIndex & parent) const;
    Q_INVOKABLE virtual
    void           fetchMore(const QModelIndex & parent);
    //Fetches any available data for the items with the parent specified by the
    //parent index.
    //Reimplement this if you are populating your model incrementally.
    //The default implementation does nothing.


    //enum Qt::SortOrder { AscendingOrder, DescendingOrder };
    virtual void sort(int column, Qt::SortOrder order = Qt::AscendingOrder);
    //Sorts the model by column in the given order.
    //The base class implementation does nothing.


/*
enum Qt::DropAction { //本枚举类用于描述模型视图里的拖动操作的语义:复制、剪切或超链接。
    CopyAction       = 0x   1, //Copy the data to the target.
    MoveAction       = 0x   2, //Move the data from the source to the target.
    LinkAction       = 0x   4, //Create a link from the source to the target.
    ActionMask       = 0x  ff,
    TargetMoveAction = 0x8002, //在 Windows上,当 D&D数据的所有权应被目标应用程序接管时,
        //即源应用程序不应删除这些数据时,会使用此值。
        //在X11上,此值用于执行移动操作。Mac上不使用TargetMoveAction。
    IgnoreAction     = 0x   0  //Ignore the action (do nothing with the data).
};
Q_DECLARE_FLAGS(DropActions, DropAction)
Q_DECLARE_OPERATORS_FOR_FLAGS(DropActions)
*/
    //Returns the actions supported by the data in this model.
    //The default implementation returns supportedDropActions().
    //Reimplement this function if you wish to support additional actions.
    //supportedDragActions() is used by QAbstractItemView::startDrag() as the
    //  default values when a drag occurs.
    virtual Qt::DropActions supportedDragActions() const;

    virtual Qt::DropActions supportedDropActions() const;
    //Returns the drop actions supported by this model.
    //The default implementation returns Qt::CopyAction.
    //Reimplement this function if you wish to support additional actions.
    //You must also reimplement the dropMimeData() function to handle the
    //  additional operations.
    //返回此模型支持的丢弃操作。默认实现返回 Qt::CcopyAction。如果您希望支持其他操作,请重写此函数。
    //同时,您还必须重写 dropMimeData()函数,以处理其他操作。


    //Note: The base class implementation of this function does nothing and returns false.
    //On models that support this, inserts count rows into the model before the given row.
    //Items in the new row will be children of the item represented by the
    //  parent model index.
    //If row is 0, the rows are prepended to any existing rows in the parent.
    //If row is rowCount(), the rows are appended to any existing rows in the parent.
    //If parent has no children, a single column with count rows is inserted.
    //Returns true if the rows were successfully inserted; otherwise returns false.
    //If you implement your own model,
    //  you can reimplement this function if you want to support insertions.
    //Alternatively, you can provide your own API for altering the data.
    //In either case, you will need to call beginInsertRows() and
    //  endInsertRows() to notify other components that the model has changed.
    //本基类并没有实现本函数的语义。本基类的子类模型必须要实现本函数,并完成信号的触发。
    virtual   //在父节点 parent 里的行列表里,在行 row 处插入 count 行元素。
    bool insertRows(int row, int count, const QModelIndex & parent = QModelIndex());
    inline
    bool insertRow (int row,            const QModelIndex & parent = QModelIndex())
    { return insertRows(arow, 1, parent); } //在行 row 的前面插入一行,成功返 true败返 false。
    //Inserts a single row before the given row in the child items of the parent specified.
    //Returns true if the row is inserted; otherwise returns false.


    //On models that support this,
    //moves count rows starting with the given sourceRow under parent sourceParent to
    //  row destinationChild under parent destinationParent.
    //Returns true if the rows were successfully moved; otherwise returns false.
    //The base class implementation does nothing and returns false.
    //If you implement your own model,
    //you can reimplement this function if you want to support moving.
    //Alternatively, you can provide your own API for altering the data.
    //把源表 sourceParent里的从行 sourceRow开始的 count行移动到目标表格里的行 destinationChild处。
    virtual
    bool    moveRows   (const QModelIndex & sourceParent, int sourceRow   , int count,
                        const QModelIndex & destinationParent, int destinationChild);
    bool    moveRow    (const QModelIndex & sourceParent, int sourceRow,
                        const QModelIndex & destinationParent, int destinationChild)
    {
        return moveRows(sourceParent, sourceRow, 1, destinationParent, destinationChild);
    }
    //On models that support this,
    //moves sourceRow from sourceParent to destinationChild under destinationParent.
    //Returns true if the rows were successfully moved; otherwise returns false.
    inline  //注意,本函数并不是虚函数,不会被子类重写。


    //On models that support this,
    //removes count rows starting with the given row under parent parent from the model.
    //Returns true if the rows were successfully removed; otherwise returns false.
    //The base class implementation does nothing and returns false.
    //If you implement your own model,
    //  you can reimplement this function if you want to support removing.
    //Alternatively, you can provide your own API for altering the data.
    virtual   //本基类无实现。语义是删除父节点 parent里 行 row开始的 count 行条目。
    bool removeRows(int row, int count, const QModelIndex & parent = QModelIndex());
    inline
    bool removeRow (int row,            const QModelIndex & parent = QModelIndex())
    { return removeRows(row, 1, aparent); } //将 parent 表格里的行 row 删除。
    //Removes the given row from the child items of the parent specified.
    //Returns true if the row is removed; otherwise returns false.


    //On models that support this,
    //inserts count new columns into the model before the given column.
    //The items in each new column will be children of the item represented by the
    //  parent model index.
    //If column is 0, the columns are prepended to any existing columns.
    //If column is columnCount(), the columns are appended to any existing columns.
    //If parent has no children, a single row with count columns is inserted.
    //Returns true if the columns were successfully inserted; otherwise returns false.
    //The base class implementation does nothing and returns false.
    virtual      //本基类并未实现列插入的语义。
    bool insertColumns(int column, int count, const QModelIndex & parent = QModelIndex());
    inline
    bool insertColumn (int column,            const QModelIndex & parent = QModelIndex())
    { return insertColumns(acolumn, 1, aparent); } //在 parent表格里的 column列处插入新的一列
    //Inserts a single column before the given column in the child items of the
    //  parent specified.
    //Returns true if the column is inserted; otherwise returns false.


    //On models that support this, moves count columns starting with the
    //  given sourceColumn under parent sourceParent to
    //  column destinationChild under parent destinationParent.
    //Returns true if the columns were successfully moved; otherwise returns false.
    //The base class implementation does nothing and returns false.
    virtual
    bool    moveColumns(const QModelIndex & sourceParent, int sourceColumn, int count,
                        const QModelIndex & destinationParent, int destinationChild);
    inline  //注意,本函数并不是虚函数,不会被子类重写。
    bool    moveColumn (const QModelIndex & sourceParent, int sourceColumn,
                        const QModelIndex & destinationParent, int destinationChild)
    {
        return moveColumns(sourceParent, sourceColumn, 1,
                           destinationParent, destinationChild);
    }
    //On models that support this,
    //moves sourceColumn from sourceParent to destinationChild under destinationParent.


    //On models that support this, removes count columns starting with the
    //  given column under parent parent from the model.
    //Returns true if the columns were successfully removed; otherwise returns false.
    //The base class implementation does nothing and returns false.
    virtual      //本基类并未实现列删除的语义。
    bool removeColumns(int column, int count, const QModelIndex & parent = QModelIndex());
    inline
    bool removeColumn (int column,            const QModelIndex & parent = QModelIndex())
    { return removeColumns(column, 1, aparent); } //删除 parent表格里的第 column列。
    //Removes the given column from the child items of the parent specified.
    //Returns true if the column is removed; otherwise returns false.

    //Returns a list of indexes for the items in the column of the
    //  start index where data stored under the given role matches the specified value.
    //The way the search is performed is defined by the flags given.
    //返回一个索引列表,该列表中的索引对应于起始索引所在列中的项,
    //在这些项中,存储在指定角色下的数据与指定的值相匹配。搜索的执行方式由提供的标志定义。
    //返回的列表可能为空。此外,请注意,如果使用了代理模型,则列表中结果的顺序可能与模型中的顺序不一致。
    //不能依赖结果的顺序。
    //The search begins from the start index,
    //  and continues until the number of matching data items equals hits,
    //  the search reaches the last row,
    //  or the search reaches start again -
    //  depending on whether MatchWrap is specified in flags.
    //If you want to search for all matching items, use hits = -1.
    //By default, this function will perform a wrapping,
    //  string-based comparison on all items,
    //  searching for items that begin with the search term specified by value.
    //Note: The default implementation of this function only searches columns.
    //  Reimplement this function to include a different search behavior.
    //基类实现:在 条目 start所在列里查找 role数据也为 value的条目集合,
    //查找数量由 hits指定,查找方式由 flags参数指定。
    Q_INVOKABLE virtual
    QModelIndexList   match(const QModelIndex & start, int role    ,
                            const QVariant    & value, int hits = 1,
                            Qt::MatchFlags      flags =
                            Qt::MatchFlags(Qt::MatchStartsWith | Qt::MatchWrap)) const;


    //Returns the model's role names.即角色集合。
    //display、decoration、edit、toolTip、statusTip、whatsThis。
    virtual QHash<int, QByteArray> roleNames() const;
    //应该是返回本模型里的元素上有哪几个角色的数据


protected: //在自己实现模型时需要调用这些成员函数,完成增删改行列的操作。
    //只用官方提供的模型的话,就用不上这些成员函数。

    //Begins a row insertion operation.
    //When reimplementing insertRows() in a subclass,
    //  you must call this function before inserting data into the
    //  model's underlying data store.   // 将在 parent指向的条目的子表里插入。
    //The parent index corresponds to the parent into which the new rows are inserted;
    //first and last are the row numbers that the
    //  new rows will have after they have been inserted.
    //要在 perent的子表里插入行,这些新行占据的下标范围是[first, last]。
    //Note: This function emits the rowsAboutToBeInserted() signal which
    //  connected views (or proxies) must handle before the data is inserted.
    //Otherwise, the views may end up in an invalid state.
    void    beginInsertRows(const QModelIndex & parent, int first, int last);
    void      endInsertRows();    //这俩保护权限的成员函数将发送信号通知视图与代理。
    //结束行的插入操作。
    //在子类中重写insertRows()时,必须在向模型的底层数据存储插入数据后调用此函数。

    //Begins a row move operation.
    //在重新实现子类时,此方法简化了模型中实体的移动操作。
    //该方法负责移动模型中的持久索引,而您原本需要亲自动手完成这些操作。
    //使用`beginMoveRows`和`endMoveRows`可以替代直接调用ayoutAboutToBeChanged 和
    //  `layoutChanged`以及调用`changePersistentlndex`。
    //sourceFirst`和`sourceLast`分别是将要移动sourceParent`索引对应的是
    //  移动行所在的父级的行对应的起始和结束行号。
    //`destinationParent'索引对应的是这些行将被移动到的父级。
    //destinationChild`则是这些行将被移动到的行,
    //即`sourceParent`中`sourceFirst'处的行在之后是直到`sourceLast'为止的所有其他行。
    //destinationParent'中将变成destinationchild'。
    //然而,当在同一父级(源父级和目的父级相等)中向下移动行时,这些行将被放置在目的子项索引之前。
    //也就是说,如果你想移动行0和 1,使它们成为行1和2,那么目的子项应设为 3。
    //在这种情况下源行的新索引(位于源首行和源末行之间)等于(目的子项-源末行-1+i)。
    //请注意,如果`sourceParent`和`destinationParent`相同,
    //  则必须确保`destinationchild`不在sourceFirst`和`sourceLast+1`的范围之内。
    //还必须确保不尝试将一行移动到其自身子项或祖先之的位置。
    //如果上述条件中任一条件为真,则此方法将返回`false`,此时应中止您的移动操作。
    bool      beginMoveRows(const QModelIndex & sourceParent,
                            int sourceFirst, int sourceLast,
                            const QModelIndex & destinationParent, int destinationRow);
    void        endMoveRows();
    //把 sourceParent子表里的行[sourceFirst, sourceLast],
    //  移动到新表 destinationParent里的行下标为 destinationRow 的起始位置。
    //这些保护权限的成员函数,不是虚函数,就是不允许被子类修改。
    //可见,这些成员函数由 Qt大师们实现了极其重要的功能。

    //开始行删除操作。
    //在子类中重写removeRows()时,必须在从模型的底层数据存储中删除数据之前调用此函数。
    //父索引对应于从其中删除新行的父项;first和last是要删除的行的行号。
    //注:此函数会发出“rowsAboutToBeRemoved”信号,
    //  与之相连的视图(或代理)必须在数据被移除之前处理此信号。否则,这些视图可能会处于无效状态。
    void    beginRemoveRows(const QModelIndex & parent, int first, int last);
    void      endRemoveRows();


    //行和列具有对称性,为了节省时间,就不写注释了。
    void beginInsertColumns(const QModelIndex & parent, int first, int last);
    void   endInsertColumns();

    bool   beginMoveColumns(const QModelIndex & sourceParent,
                            int sourceFirst, int sourceLast,
                            const QModelIndex & destinationParent, int destinationColumn);
    void     endMoveColumns();

    void beginRemoveColumns(const QModelIndex & parent, int first, int last);
    void   endRemoveColumns();


    //typedef QList<QModelIndex> QModelIndexList;
    //Returns the list of indexes stored as persistent indexes in the model.
    QModelIndexList         persistentIndexList() const; //返回模型里存储的持久索引。
    //Changes the QPersistentModelIndex that is equal to the
    //  given from model index to the given to model index.
    //If no persistent model index equal to the given from model index was found,
    //  nothing is changed.
    void              changePersistentIndex(    const QModelIndex     & from,
                                                const QModelIndex     & to   );
    void              changePersistentIndexList(const QModelIndexList & from,
                                                const QModelIndexList & to   );
    //Changes the {QPersistentModelIndex}es that are equal to the indexes in the
    //  given from model index list to the given to model index list.
    //If no persistent model indexes equal to the
    //  indexes in the given from model index list are found, nothing is changed.



    void encodeData(const QModelIndexList & indexes, QDataStream & stream) const;//无注释

    bool decodeData(int row, int column,    //无注释,太好了
                    const QModelIndex     & parent , QDataStream & stream);

    //Begins a model reset operation.
    //A reset operation resets the model to its current state in any attached views.
    //Note: Any views attached to this model will be reset as well.
    //当模型被重置时,意味着该模型之前报告的任何数据现在都无效,必须重新查询。
    //这也意味着当前项和任何选中的项都将变得无效。
    //当模型大幅改变其数据时,有时候直接调用这个函数可能比发出`dataChanged()、信号来得更简单,
    //  从而在底层数据源或其结构发生变化时通知其他组件。
    //在重置模型或代理模型中的任何内部数据结构之前,必须调用此函数。
    //比函数会发出信号modelAboutToBeReset()。
    void    beginResetModel();
    void      endResetModel();
    //完成模型重置操作。
    //在重置模型或代理模型中的任何内部数据结构后,必须调用此函数。
    //此函数发出信号modelReset()。


public    Q_SLOTS:
    //让模型知道它应该将缓存的信息提交到永久存储。此功能通常用于行编辑。
    //如果没有错误则返回true;否则返回false。
    virtual bool submit();
    virtual void revert();  //revert恢复
    //让模型知道它应该丢弃缓存的信息。此函数通常用于行编辑。


protected Q_SLOTS:
    virtual void resetInternalData();
    //此插槽在模型内部数据被清除并在重置时调用。
    //此插槽提供了对具体代理模型子类的便利,例如维护额外数据的OSortFilterProxyModel子类。


Q_SIGNALS:
    //This signal is emitted whenever the data in an existing item changes.
    //If the items are of the same parent,
    //the affected ones are those between topLeft and bottomRight inclusive.
    //如果这些项目属于同一个父项,受影响的那些是包括 topLeft和 bottomRight之间的。
    //If the items do not have the same parent, the behavior is undefined.
    //When reimplementing the setData() function, this signal must be emitted explicitly.
    //在重新实现,自定义 setData() 函数时,必须显式地发出此信号。
    //The optional roles argument can be used to specify
    //  which data roles have actually been modified. An empty vector in the
    //roles argument means that all roles should be considered modified.
    //The order of elements in the roles argument does not have any relevance.
    void    dataChanged(const QModelIndex & topLeft, //两个索引指向的条目应有共同的父类
                        const QModelIndex & bottomRight,
                        const QList<int>  & roles = QList<int>());

    //This signal is emitted whenever a header is changed.
    //The orientation indicates whether the horizontal or vertical header has changed.
    //The sections in the header from the first to the last need to be updated.
    //表头里的列 [first, last]变化了,需要更新。
    void headerDataChanged(Qt::Orientation orientation, int first, int last);
    //在重实现setHeaderData()函数时,必须显式地发出此信号。
    //如果要更改列数或行数,则不需要发出此信号,而是使用 begin/end 函数
    //(有关详细信息,请参阅QAbstractltemModel类描述中有关子类化的部分)。

    //This enum describes the way the model changes layout.
    //请注意,VerticalSortHint和 HorizontalSortHint表示这些项是在同一个父容器内进行移动,
    //  而不是在模型中被移动到不同的父容器中,也不是被过滤掉或加入进来。
    enum LayoutChangeHint
    {
        NoLayoutChangeHint,  //No hint is available.
          VerticalSortHint,  //Rows    are being sorted.
        HorizontalSortHint   //Columns are being sorted.
    };
    Q_ENUM(LayoutChangeHint)

    //This signal is emitted just before the layout of a model is changed.
    //Components connected to this signal use it to adapt to changes in the model's layout.
    //Subclasses should update any persistent model indexes after
    //  emitting layoutAboutToBeChanged().
    //The optional parents parameter is used to give a more specific
    //  notification about what parts of the layout of the model are changing.
    //An empty list indicates a change to the layout of the entire model.
    //The order of elements in the parents list is not significant.
    //The optional hint parameter is used to give a
    //  hint about what is happening while the model is relayouting.
    //在对模型进行排序操作时,会触发本信号,以进行相关更新。
    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);
    //每当模型所展示的项的布局发生变化时,就会发出这个信号;
    //例如,当模型被排序时。当视图接收到这个信号时,应更新项的布局以反映这一变化。
    //在子类化QAbstractItemModel或QAbstractProxyModel时,
    //  请确保在更改项目的顺序或更改向视图公开的数据的结构之前发出layoutAboutToBeChanged(),
    //  并在更改布局后发出layoutChanged()。
    //子类应在发出layoutchanged()之前更新任何持久的模型索引。换句话说,当结构发生变化时:
    //  emit layoutAboutToBeChanged       //这里指出了更新模型时的函数调用顺序。
    //  Remember the QModelIndex that will change
    //  Update your internal data
    //  Call changePersistentIndex()
    //  emit layoutChanged

    //当调用beginResetModel()时发出此信号,在模型内部状态(例如持久化模型索引)被无效化之前。
    //注意:这是一个私有信号。它可以在信号连接中使用,但不能由用户发出。
    void        modelAboutToBeReset(QPrivateSignal);
    void                 modelReset(QPrivateSignal);
    //当调用endResetModel()时,此信号被触发,在模型内部状态(例如持久化模型索引)已失效后。
    //清注意,如果模型被重置,应认为之前从中获取的所有信息都是无效的。
    //这包括但不限于rowCount()和 columncount()、flags()、通过data()检索的数据,以及roleNames()。

    /* protected :
    void    beginInsertRows(const QModelIndex & parent, int first, int last);
    void      endInsertRows();

    bool      beginMoveRows(const QModelIndex & sourceParent,
                            int sourceFirst, int sourceLast,
                            const QModelIndex & destinationParent, int destinationRow);
    void        endMoveRows();

    void    beginRemoveRows(const QModelIndex & parent, int first, int last);
    void      endRemoveRows();
    */
    //This signal is emitted just before rows are inserted into the model.
    //The new items will be positioned between start and end inclusive,
    //  under the given parent item. //parent子表里的 [first, last]要设置为新行。
    //注:连接到此信号的零部件使用它来适应模型尺寸的变化。
    //它只能由 QAbstractltemModel实现发出,而不能在子类代码中显式发出。
    //注意:这是一个私有信号。它可以在信号连接中使用,但不能由用户发出。
    void      rowsAboutToBeInserted(const QModelIndex & parent,
                                    int first, int last, QPrivateSignal);
    void               rowsInserted(const QModelIndex & parent,
                                    int first, int last, QPrivateSignal);
    //This signal is emitted after rows have been inserted into the model.

    //以下操作,在业务层面是对称等价的,不再阅读文档了。
    void         rowsAboutToBeMoved(const QModelIndex & sourceParent,
                                    int sourceStart, int sourceEnd,
                                    const QModelIndex & destinationParent,
                                    int destinationRow, QPrivateSignal);
    void                  rowsMoved(const QModelIndex & parent,
                                    int start, int end,
                                    const QModelIndex & destination,
                                    int            row, QPrivateSignal);

    void       rowsAboutToBeRemoved(const QModelIndex & parent,
                              int first, int last, QPrivateSignal);
    void                rowsRemoved(const QModelIndex & parent,
                     int first, int last, QPrivateSignal);


    void   columnsAboutToBeInserted(const QModelIndex & parent,
                                    int first, int last, QPrivateSignal);
    void            columnsInserted(const QModelIndex & parent,
                                    int first, int last, QPrivateSignal);


    void      columnsAboutToBeMoved(const QModelIndex & sourceParent,
                                    int sourceStart, int sourceEnd,
                                    const QModelIndex & destinationParent,
                                    int destinationColumn, QPrivateSignal);
    void               columnsMoved(const QModelIndex & parent,
                                    int start, int end,
                                    const QModelIndex & destination,
                                    int column, QPrivateSignal);

    void    columnsAboutToBeRemoved(const QModelIndex & parent,
                                    int first, int last, QPrivateSignal);
    void             columnsRemoved(const QModelIndex & parent,
                                    int first, int last, QPrivateSignal);

}; //完结 class QAbstractItemModel : public QObject
Q_DECLARE_OPERATORS_FOR_FLAGS(QAbstractItemModel::CheckIndexOptions)

(4)

谢谢

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zhangzhangkeji

谢谢支持

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值