參考: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信息,這樣
- 每個節點可以查詢子節點數量
- 每個節點可以查詢到自身數據
- 可以根據NodeInfo信息(row/col/this)獲取到QModeIndex
- 數據構造時,形成NodeInfo的樹形層次
- QAbstractItemModel的接口中,index函數中綁定NodeInfo
- 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 }
