在Qt中,模型視圖框架是許多應用程序的核心。這種框架使用模型來表示數據,使用視圖(如QTableView或QTreeView)來將該數據可視化。Qt中提供了一些內置的模型類,但是,如果您需要為自己的應用程序定義自定義的數據源,那麼您需要了解QAbstractItemModel的工作方式。
一、QAbstractItemModel簡介
QAbstractItemModel是Qt的一個關鍵類,它為開發人員提供了一個介面,用於指定模型數據的組織方式。它是QAbstractTableModel和QAbstractListModel等模型的基類,這些模型提供了一些常見的實現,例如表格和列表。QAbstractItemModel用於QTreeView,QListView,QTableView等視圖類的基類,它們都使用基於文件夾的數據模型來顯示數據。
QAbstractItemModel所有直接的子類應該在以下一個函數中實現兩個不同的索引:index()和parent()。這些函數定義了靜態樹形結構,元素的位置不會改變。這些函數能夠讓Qt高效地處理大型樹形結構。index()和parent()會被Qt視圖類用於將數據排列為TreeView,ListView和TableView等典型模型視圖結構。
二、QAbstractItemModel的子類實現
1、自定義QAbstractItemModel
class CustomModel : public QAbstractItemModel { public: CustomModel(QObject *parent = 0); ~CustomModel(); QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; QModelIndex parent(const QModelIndex &child) const; int rowCount(const QModelIndex &parent = QModelIndex()) const; int columnCount(const QModelIndex &parent = QModelIndex()) const; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); };
上面是一個自定義的QAbstractItemModel的框架。在這個例子中,根節點是一個空的QModelIndex,它沒有坐標以及沒有父節點。可以看到,index()和parent()都需要返回一個QModelIndex,它們指定了行和列的位置。rowCount()和columnCount()函數返回模型中行的數量和列的數量。
在此例子中,data()和setData()函數的實現也是必不可少的。它們定義了數據將如何存儲和訪問。在大多數情況下,將使用QVariant來存儲數據,而且在data()函數中使用role參數來返回適合給定視圖類型的數據。setData()負責更新模型數據。
2、Qt自帶的Model Index
QModelIndex QAbstractItemModel::index(int row, int column, const QModelIndex &parent = QModelIndex()) const
index()函數返回一個QModelIndex對象,此對象由行號和列號組成,該索引屬於parent。在許多情況下,一些QAbstractItemModel的派生類經常使用這些方法來創建一個自己的index()。
3、返回父級QModelIndex
QModelIndex QAbstractItemModel::parent(const QModelIndex &index) const
parent()函數返回一個QModelIndex對象,該對象傳遞迴索引的父級項的位置。parent()和index()通常應該是相互的逆。parent()為頂級ItemModel或已知索引返回無效的QModelIndex。因此,QModelIndex的行號和列號都是0。
4、獲取行數和列數
int QAbstractItemModel::rowCount(const QModelIndex &parent = QModelIndex()) const int QAbstractItemModel::columnCount(const QModelIndex &parent = QModelIndex()) const
這兩個函數返回模型中給定父項的行數或列數。如果沒有父項,則返回頂層項的行數或列數。row()和column()一樣,都從0開始計數。在許多情況下,這些函數將用於初始化一個ItemView部件。
5、獲取和設置ItemData
QVariant QAbstractItemModel::data(const QModelIndex &index, int role = Qt::DisplayRole) const bool QAbstractItemModel::setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole)
data()函數返回與給定模型索引關聯的數據。可以為給定角色請求數據。setData()函數將給定值存儲在模型索引處。如果此處發生錯誤,則使用Rollback數據。
三、QAbstractItemModel的應用舉例
1、創建樹型結構
這個應用程序是一個樹型表格。它的數據源是硬編碼,但該例子很好地展示了如何擴展QAbstractItemModel來支持樹型結構:
class TreeModel : public QAbstractItemModel { Q_OBJECT public: TreeModel(QObject *parent = 0); ~TreeModel(); QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; QModelIndex parent(const QModelIndex &child) const; int rowCount(const QModelIndex &parent = QModelIndex()) const; int columnCount(const QModelIndex &parent = QModelIndex()) const; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); private: TreeItem *rootItem; };
具體的實現過程就不再貼出,可以參考Qt自帶例子,這裡給出參考:
2、擴展現有的模型類
下面是一個QAbstractItemModel的派生類,該類從QAbstractListModel擴展:
class StringListModel : public QAbstractListModel { Q_OBJECT public: explicit StringListModel(const QStringList &strings, QObject *parent = nullptr) : QAbstractListModel(parent), stringList(strings) { } int rowCount(const QModelIndex &parent = QModelIndex()) const override { if (parent.isValid()) return 0; return stringList.count(); } QVariant data(const QModelIndex &index, int role) const override { if (!index.isValid()) return QVariant(); if (index.row() >= stringList.size()) return QVariant(); if (role == Qt::DisplayRole) return stringList.at(index.row()); else return QVariant(); } private: QStringList stringList; };
StringListModel擴展了QAbstractListModel並實現了rowCount()和data()函數來處理一個QStringList中的內容。這是一個非常基本的示例,但當您需要單行列表模型時,這可能是一個很有用的例子。
3、處理排序和過濾
排序和過濾是QAbstractItemModel的高級應用。排序需要將數據按特定順序排列,而過濾則需要以某種方式選擇數據,例如將其篩選掉。這是一個基本示例:
class SortFilterModel : public QSortFilterProxyModel { public: SortFilterModel(QObject *parent = nullptr) : QSortFilterProxyModel(parent) { } bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override { QModelIndex index0 = sourceModel()->index(source_row, 0, source_parent); QRegExp regExp("^\\[0-9\\.]+(.*)"); QString str = index0.data(Qt::DisplayRole).toString(); if (regExp.indexIn(str) != -1) { QString capStr = regExp.cap(1); if (capStr < "30") return false; } return true; } };
在此示例中,過濾器使用QRegExp來查找所有標題是數字(例如,[20]Title 3)的行。如果標題中的數字小於30,則該行將被過濾掉。
四、總結
QAbstractItemModel為開發者提供了一個用於管理自定義數據的模型視圖框架。開發者可以通過繼承並實現QAbstractItemModel的相關函數來創建自己的模型,或者繼承並擴展現有的模型類。此外,QAbstractItemModel還支持排序和過濾。學會使用QAbstractItemModel可以讓應用程序在數據管理方面完美地運轉。
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/293321.html