一杯清酒邀明月
天下本无事,庸人扰之而烦耳。

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

 

posted on 2020-08-17 11:01  一杯清酒邀明月  阅读(4086)  评论(0编辑  收藏  举报