参考: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 }