QT qml TreeView展示数据结构于界面
Class QAbstractItemModel:
使用QML的TreeView类来展示树状的结构,对应的是QT的Model/View模型。这个model是一个数据模型,要为TreeView提供一个模型,需要定义一个类,该类需要继承自calss QAbstractItemModel,不能直接使用该类。
另外,If you need a model to use with an item view such as QML's List View element or the C++ widgets QListView or QTableView, you should consider subclassing QAbstractListModel or QAbstractTableModel instead of this class.
定义的模型可以是有层次关系的(即有item含有孩子),模型被传递给Views和delegates. 如果模型没有层次关系,那么就指示一个简单的表格,表中的每个元素(item)都有唯一的index,index是 calss QModelIndex的对象,The QModelIndex class is used to locate data in a data model.
- 模型中的每一个Item对应一个model index, 可以通过QAbstractItemModel::index函数来获取,但是该函数式纯虚函数,需要使用者自己实现,具体实现方法??
- Each item has a number of data elements associated with it ,each with its own role, and these elements 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. The roles are used by the view to indicate to the model which type of data it needs(View使用这些roles来告诉模型,自己需要模型的哪一中数据来显示在图形上). ---------- 没大明白,指的是模型中的每一个item都有很多属性吗,然后每一个属性对应着一个唯一的role,说属性的值就相当于说该属性的role的值?
- 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().---- Qt::ItemDataRole的作用是设置某个item的某个role对应的值。
- Items can be queried with flags() (see Qt::ItemFlag) to see if they can be selected, dragged, or manipulated in other ways.---flags()为虚函数。
- If an item has child objects, hasChildren() returns true for the corresponding index.----hasChildren()是虚函数。
- 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().-----rowCount() and a columnCount()是纯虚函数。
- 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.
- The items available through the model can be searched for particular data using the match() function.
To sort the model, you can use sort().
继承该类的注意事项:
1)继承该类时,以下几个函数必须自己实现:
index(), parent(), rowCount(), columnCount(), and data(). 这几个函数在所有的read-only模型中都会用到,而且是editable model的基础。
2)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. -----??
3)为了使你的模型可以编辑,必须实现setData()函数,,还有flags()函数(保证ItemIsEditable 被返回),你也可以重新实现headerData()和setHeaderData()来控制模型的Header的展现方式。
4)dataChanged()和headerDataChanged()信号必须被显式地发出,当重新实现setData()和setHeaderData()函数时。
5)调用creatIndex()函数,来为模型的特定的一个item建立一个index,其他函数可以使用这个index来操作该item. 该函数接受3个参数,QModelIndex createIndex(int row, int column, void * ptr = 0),对于第三个参数的作用我不知道,但是QT5.5文档中有个例子“Simple Tree Model Example”
6)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. ----- 没理解呢?
7)这一项我用过,哈哈,相当重要
只不过我没有重新实现现成的insertRows(), insertColumns()...,只是使用了beginInsertRows()这种信号。
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:
An insertRows() implementation must call beginInsertRows() before inserting new rows into the data structure, and endInsertRows() immediately afterwards.
An insertColumns() implementation must call beginInsertColumns() before inserting new columns into the data structure, and endInsertColumns() immediately afterwards.
A removeRows() implementation must call beginRemoveRows() before the rows are removed from the data structure, and endRemoveRows() immediately afterwards.
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.
8)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.
-------------
QAbstractItemModel的有用的成员:
1) void QAbstractItemModel::beginResetModel()
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.
When a model is reset it means that any previous data reported from the model is now invalid and has to be queried for again. This also means that the current item and any selected items will become invalid.
When a model radically changes its data it can sometimes be easier to just call this function rather than emit dataChanged() to inform other components when the underlying data source, or its structure, has changed.
You must call this function before resetting any internal data structures in your model or proxy model.This function emits the signal modelAboutToBeReset().This function was introduced in Qt 4.6.
----我用了这个函数后,界面上的TreeView会全部收缩起来,太气人了。
2) QAbstractItemModel::dataChanged----- 【signal】
void QAbstractItemModel::dataChanged(const QModelIndex & topLeft, const QModelIndex & bottomRight, const QVector<int> & roles = QVector<int> ())
我用过:如果改变了模型中树结构上的某一个节点的属性,改完之后,可以调用emit dataChanged(modelindex, modelindex),然后界面上的树对应的该节点会相应的改变,modelindex指的是改节点的modelindex,最后一个入参我没有使用它.
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---说的是简单的网格结构吧. If the items do not have the same parent, the behavior is undefined.
When reimplementing the setData() function, this signal must be emitted explicitly.
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.
3) QAbstractItemModel::beginInsertRows(const QModelIndex & parent, int first, int last)----------protected 成员函数
When reimplementing insertRows() in a subclass, you must call this function before inserting data into the model's underlying data store.
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.
我在处理TreeView时用过,如果要在一个父节点下插入新的孩子,则parent指的是该父节点对应的index,另外两个参数对应的是插入的位置。具体见qt文档,相当详细,其他的begin..都大体类似,注意begin..要与end..成对使用。
Note: This function emits the rowsAboutToBeInserted() signal which connected views (or proxies) must handle before the data is inserted.
4)beginMoveRows, beginRemoveColumns....... 都是很有用的信号。
5)columnCount(const QModelIndex & parent = QModelIndex()) const,纯虚函数
Returns the number of columns for the children of the given parent.
Related: rowCount();
6) QModelIndex QAbstractItemModel::createIndex(...)---------------????没明白
Creates a model index for the given row and column with the internal pointer ptr.
7) QVariant QAbstractItemModel::data(const QModelIndex & index, int role = Qt::DisplayRole) const---------????没明白
Returns the data stored under the given role for the item referred to by the index.
Note: If you do not have a value to return, return an invalid QVariant instead of returning 0.
8)其他不太理解的函数:
buddy, canDropMimeData, canFetchMore, changePersistentIndex,dropMimeData,match,扥等。看来该类给用户提供了很多虚函数,可以让使用者去重新实现,很好地对类的功能进行了细分和规划。
-------------------------------------------------------------------------
QT中与QAbstractItemModel类相似的类还有 QAbstractListModel ,但是 QAbstractListModel 类只能提供一维的模型,适用于为QListView提供模型:
“The QAbstractListModel class provides an abstract model that can be subclassed to create one-dimensional listmodels.
QAbstractListModel provides a standard interface for models that represent their data as a simple non-hierarchical sequence of items. It is not used directly, but must be subclassed.
Since the model provides a more specialized interface than QAbstractItemModel, it is not suitable for use with tree views; you will need to subclass QAbstractItemModel if you want to provide a model for that purpose. If you need to use a number of list models to manage data, it may be more appropriate to subclass QAbstractTableModel instead.”
----------------------------------------------------------------------------
QT文档自带的例子:
1)在qt creator Help中搜索:Simple Tree Model Example---应该会很好吧。
2)
相关资源:
1)博客例子: https://blog.csdn.net/shado_walker/article/details/56495059