Qt系列文章之 QAbstractItemModel(中)
上一篇文章基于QAbstractItemModel新建了一個用戶模型類,此文緊接上一篇文章來對用戶模型進行具體設計和實現。
QAbstractItemModel
生成的用戶模型給出了模型的標準接口;但是任何模型都是對數據封裝,那么必然需要專用對象來儲存數據,而這個儲存數據的對象就具有十分多的形式,可以是Qt/C++容器、數組、字符串、文件、SQL對象等。而用戶類就是將用戶各種形式的數據儲存方式轉為統一的模型接口以供其他類(如視圖類)來使用,同時將其他類的操作轉化到對具體數據對象的具體操作(如寫、添加、刪除等)。
此處為了簡化接口,構造一個常見的Table類用戶模型,模型一共兩列,每行第一列儲存“Name“格式是QString,每行第二列儲存“Age”格式是int。采用QMap<QString,int>來儲存每一行的數據,采用QVector<QPair<QString,int>>來儲存所有行的數據。在h文件中私有屬性定義一個數據儲存指針:
QVector<QPair<QString,int>> *m_dataVector = nullptr; //新建一個儲存數據的序列對象,每個元素(行)兩個值,一個儲存姓名、一個儲存年齡
同時定義一個QList m_headName來儲存表頭名稱。
在cpp構造函數中對數據儲存指針進行初始化并給數據列表初始化一個默認值:
在析構函數中對數據列表進行析構:
CustomItemModel::~CustomItemModel() {if(m_dataVector) {m_dataVector->clear();delete m_dataVector;m_dataVector=nullptr;} }構造好數據儲存形式之后,下一步就可以對用戶模型的虛函數進行實現。這些虛函數的實現與用戶自定義的數據結構和需求精密相關,沒有具體實現方式可以參考,需根據具體場景來編寫實現代碼。
- headerData(int section, Qt::Orientation orientation, int role)
獲取表頭信息,orientation表示表頭方向,分為水平和垂直;section表示表頭位置,如果是行,表示第幾列;如果是列,表示第幾行。Role表示表頭角色信息。Model模型每個元素提供的role主要與如下一些。
此處我們只關心行表頭,同時也只希望返回表頭的顯示信息即DisplayRole的值。一個簡單的表頭信息獲取實現代碼如下:
QVariant CustomItemModel::headerData(int section, Qt::Orientation orientation, int role) const {if(role!=Qt::DisplayRole)return QVariant();if(orientation==Qt::Vertical)return QVariant(section);if(orientation==Qt::Horizontal){if(section==0) return QVariant(m_headName[0]);if(section==1) return QVariant(m_headName[1]);}return QVariant(); }- setHeaderData()
該函數實現對表頭文件信息的修改,和上一個函數正好構成一對函數。同樣,我們此處也只是暫時修改一下行表頭的信息。
bool CustomItemModel::setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role) {if (value != headerData(section, orientation, role)) {if(role!=Qt::EditRole) return false;if(orientation==Qt::Vertical) return false;if(section==0) m_headName[0]= value.toString();if(section==1) m_headName[1]=value.toString();emit headerDataChanged(orientation, section, section);return true;}return false; }- index(int row, int column, const QModelIndex &parent)
index根據表格中的父節點parent下的某行row和某列column信息獲取對應的QModelIndex對象信息。如果行和列超出范圍,返回一個無效的QModelIndex()。
QModelIndex CustomItemModel::index(int row, int column, const QModelIndex &parent) const {if(row>m_dataVector->size()-1 || row < 0) return QModelIndex();if(column>1 || column<0) return QModelIndex();return createIndex(row,column); }- parent(const QModelIndex &index)
函數實現獲取某個index的父節點,由于此處是表格模型,默認認為父節點是無效空節點。
QModelIndex CustomItemModel::parent(const QModelIndex &index) const {// FIXME: Implement me!return QModelIndex(); }- rowCount(const QModelIndex &parent)
獲取某個父節點parent下的模型行數,直接范圍數據列表的size即可:
int CustomItemModel::rowCount(const QModelIndex &parent) const {return m_dataVector->size(); }- columnCount(const QModelIndex &parent)
返回某個父節點下的模型列數,此處直接返回2:
int CustomItemModel::columnCount(const QModelIndex &parent) const {return 2; }- hasChildren(const QModelIndex &parent)
判斷某個節點是否還有子節點,這種判斷對于樹形模型來說十分重要,表格模型默認都沒有子節點:
bool CustomItemModel::hasChildren(const QModelIndex &parent) const {return false; }- canFetchMore(const QModelIndex &parent)
判斷數據是否還有更多數據節點可以獲取:
bool CustomItemModel::canFetchMore(const QModelIndex &parent) const {return false; }- fetchMore(const QModelIndex &parent)
由于沒有更多數據,此處不做額外處理:
void CustomItemModel::fetchMore(const QModelIndex &parent) {// FIXME: Implement me! }- data(const QModelIndex &index, int role)
data()和setData()函數是十分鐘的對模型元素進行操作的函數。data()函數根據角色和索引號獲取到對應的元素值。如下幾個角色比較關鍵:
此處我們暫時只關心DisplayRole的值,該函數的實現代碼如下,此處使用switch來判斷不同角色對應的值,后面可以做一些比較全面的補充:
QVariant CustomItemModel::data(const QModelIndex &index, int role) const {if (!index.isValid())return QVariant();if(index.row()>m_dataVector->size()-1 || index.row()<0 || index.column()<0 ||index.column()>1)return QVariant();switch(role){case Qt::DisplayRole:{if(index.column()==0){QString name = m_dataVector->at(index.row()).first;return QVariant(name);}if(index.column()==1){int age = m_dataVector->at(index.row()).second;return QVariant(age);}break;}- setData(const QModelIndex &index, const QVariant &value, int role)
該函數將某個元素(index指定)某個角色role的值設置為value的值,此處關注對顯示字符串的編輯角色,實現代碼如下:
bool CustomItemModel::setData(const QModelIndex &index, const QVariant &value, int role) {if (data(index, role) != value){switch (role){case Qt::EditRole:{QString name = m_dataVector->at(index.row()).first;int age = m_dataVector->at(index.row()).second;if(index.column()==0){QPair<QString,int> pair(value.toString(),age);m_dataVector->replace(index.row(),pair);}if(index.column()==1){QPair<QString,int> pair(name,value.toInt());m_dataVector->replace(index.row(),pair);}emit dataChanged(index, index, QVector<int>() << role);return true;}- flags(const QModelIndex &index)
獲取某個元素(index指定的)的所有屬性標志位,多個屬性采用按位或“|”算法鏈接,此處我們先設置如下標志位屬性。
Qt::ItemFlags CustomItemModel::flags(const QModelIndex &index) const {if (!index.isValid())return Qt::NoItemFlags;return Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable |Qt::ItemIsUserCheckable; // FIXME: Implement me! }本文對幾個關鍵的虛函數進行了實現,下一文將繼續介紹剩下幾個虛函數的實現,同時將模型集成到視圖并顯示出來。
歡迎同好溝通交流,批評指正,歡迎關注我的公號:不如起而行之
總結
以上是生活随笔為你收集整理的Qt系列文章之 QAbstractItemModel(中)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: android 大屏图表 MPAndro
- 下一篇: 网络安全——技术与实践(第3版)课后题答