Qt QAbstractItemModel使用樣例與解析


參考:qt源碼

1 qstandarditemmodel_p.h
2 qstandarditemmodel.h
3 qstandarditemmodel.cpp
4 qabstractitemmodel.h
5 qabstractitemmodel.cpp

QAbstractItemModel是一個接口類,使用時需要從它繼承下來,實現相關的函數后使用。
不同於QStandardItemModel,使用QAbstractItemModel的話,需要自己構造樹形結構數據,並在虛函數中返回對應的值。

當然,簡單使用的話,也可以快速構造出沒有父節點的簡單表格結構。
形如根節點下列了幾排幾列子節點的表格情形。

需要繼承的類有:

 1 class HistoryModel : public QAbstractItemModel  2 {  3 public:  4     explicit HistoryModel(QObject *parent = 0);  5 
 6     // 構造父節點下子節點的索引
 7     virtual QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;  8     // 通過子節點索引獲取父節點索引
 9     virtual QModelIndex parent(const QModelIndex &child) const override; 10     // 獲取父節點下子節點的行數
11     virtual int rowCount(const QModelIndex &parent = QModelIndex()) const override; 12     // 獲取父節點下子節點列數
13     virtual int columnCount(const QModelIndex &parent = QModelIndex()) const override; 14     // 獲取節點數據:包括DisplayRole|TextAlignmentRole等
15     virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; 16 };

實現幾排幾列表格情形的例子:

 1 HistoryModel::HistoryModel(QObject *parent /*= 0*/)  2  : QAbstractItemModel(parent)  3 {  4 }  5 
 6 QModelIndex HistoryModel::index(int row, int column, const QModelIndex &parent /*= QModelIndex()*/) const
 7 {  8     // 創建普通索引
 9     return createIndex(row, column); 10 } 11 QModelIndex HistoryModel::parent(const QModelIndex &child) const
12 { 13     // 父節點均為跟節點
14     return QModelIndex(); 15 } 16 int HistoryModel::rowCount(const QModelIndex &parent /*= QModelIndex()*/) const
17 { 18     // 根節點下有5行,其它行下沒有
19     if (parent.row() == -1) 20  { 21         return 5; 22  } 23     return 0; 24 } 25 int HistoryModel::columnCount(const QModelIndex &parent /*= QModelIndex()*/) const
26 { 27     // 每行有量列
28     return 2; 29 } 30 
31 QVariant HistoryModel::data(const QModelIndex &index, int role /*= Qt::DisplayRole*/) const
32 { 33     // 節點內容:左對齊,顯示行列號
34     if (role == Qt::TextAlignmentRole) 35         return int(Qt::AlignLeft | Qt::AlignVCenter); 36     else if (role == Qt::DisplayRole) 37         return QString("row=%1,col=%2").arg(index.row()).arg(index.column()); 38     else
39         return QVariant(); 40 }

進一步使用,添加樹形結構,自己構造樹形結構數據:

1 struct NodeInfo 2 { 3     QModelIndex parent;              // 父節點index
4     QString sData;                   // 自身數據
5     QVector<NodeInfo*> childNodes;   // 子節點
6     int nRow; 7     int nCol; 8     NodeInfo(QModelIndex parentIdx, QString s, int row, int col):parent(parentIdx), sData(s), nRow(row), nCol(col){} 9 };

生成如下的這種界面:兩個level=1節點,每個節點下有一些數據

可以這樣來做:
每個節點存儲一個NodeInfo信息,這樣

    1. 每個節點可以查詢子節點數量
    2. 每個節點可以查詢到自身數據
    3. 可以根據NodeInfo信息(row/col/this)獲取到QModeIndex
    4. 數據構造時,形成NodeInfo的樹形層次
    5. QAbstractItemModel的接口中,index函數中綁定NodeInfo
    6. QAbstractItemModel的其它接口中,查詢NodeInfo並使用
 1 HistoryModel::HistoryModel(QObject *parent /*= 0*/)  2  : QAbstractItemModel(parent)  3 {  4     // 創建root節點
 5     m_pRootNode = new NodeInfo(nullptr, "rootNode", -1, -1);  6     m_receiveInfo = new NodeInfo(m_pRootNode, "ReceiveMessage", 0, 0);  7     m_replyInfo = new NodeInfo(m_pRootNode, "ReplyMessage", 1, 0);  8     m_pRootNode->childNodes.append(m_receiveInfo);  9     m_pRootNode->childNodes.append(m_replyInfo); 10 } 11 
12 QModelIndex HistoryModel::index(int row, int column, const QModelIndex &parent /*= QModelIndex()*/) const
13 { 14     if (parent.row() == -1 && parent.column() == -1) 15  { 16         // 首層節點綁定關系
17         if (row < m_pRootNode->childNodes.count()) 18             return createIndex(row, column, m_pRootNode->childNodes[row]); 19  } 20     else
21  { 22         // 其它層節點綁定關系
23         if (parent.internalPointer() != nullptr) 24  { 25             NodeInfo* pNode = reinterpret_cast<NodeInfo*>(parent.internalPointer()); 26             if (pNode->childNodes.size() > row) 27  { 28                 return createIndex(row, column, pNode->childNodes[row]); 29  } 30  } 31  } 32     return QModelIndex(); 33 } 34 
35 QModelIndex HistoryModel::parent(const QModelIndex &child) const
36 { 37     if (child.internalPointer() != nullptr) 38  { 39         NodeInfo* pNode = reinterpret_cast<NodeInfo*>(child.internalPointer()); 40         NodeInfo* pParent = pNode->parent; 41         if (pParent != nullptr) 42  { 43             // 根據父節點信息:row/col/node*獲取Index
44             return createIndex(pParent->nRow, pParent->nCol, pParent);; 45  } 46  } 47     return QModelIndex(); 48 } 49 int HistoryModel::rowCount(const QModelIndex &parent) const
50 { 51     if (parent.internalPointer() == nullptr) 52  { 53         // 根節點下的數據行數
54         return m_pRootNode->childNodes.count(); 55  } 56     else
57  { 58         // 節點下的數據行數
59         NodeInfo* pNode = reinterpret_cast<NodeInfo*>(parent.internalPointer()); 60         return pNode->childNodes.size(); 61  } 62 } 63 int HistoryModel::columnCount(const QModelIndex &parent /*= QModelIndex()*/) const
64 { 65     // 每行有量列
66     return 1; 67 } 68 
69 QVariant HistoryModel::data(const QModelIndex &index, int role /*= Qt::DisplayRole*/) const
70 { 71     // 節點內容:左對齊,顯示行列號
72     if (role == Qt::TextAlignmentRole) 73  { 74         return int(Qt::AlignLeft | Qt::AlignVCenter); 75  } 76     else if (role == Qt::DisplayRole) 77  { 78         if (index.internalPointer() == 0) 79  { 80             return QString("row=%1,col=%2").arg(index.row()).arg(index.column()); 81  } 82         else
83  { 84             NodeInfo* pNode = reinterpret_cast<NodeInfo*>(index.internalPointer()); 85             return pNode->sData; 86  } 87  } 88     else
89  { 90         return QVariant(); 91  } 92 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM