QAbstractItemModel使用样例与解析

(Owed by: 春夜喜雨 http://blog.csdn.net/chunyexiyu)

参考:qt源码
qstandarditemmodel_p.h
qstandarditemmodel.h
qstandarditemmodel.cpp
qabstractitemmodel.h
qabstractitemmodel.cpp

QAbstractItemModel是一个接口类,使用时需要从它继承下来,实现相关的函数后使用。
不同于QStandardItemModel,使用QAbstractItemModel的话,需要自己构造树形结构数据,并在虚函数中返回对应的值。

当然,简单使用的话,也可以快速构造出没有父节点的简单表格结构。
形如根节点下列了几排几列子节点的表格情形。

需要继承的类有:

class HistoryModel : public QAbstractItemModel
{
public:
    explicit HistoryModel(QObject *parent = 0);

    // 构造父节点下子节点的索引
    virtual QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
    // 通过子节点索引获取父节点索引
    virtual QModelIndex parent(const QModelIndex &child) const override;
    // 获取父节点下子节点的行数
    virtual int rowCount(const QModelIndex &parent = QModelIndex()) const override;
    // 获取父节点下子节点列数
    virtual int columnCount(const QModelIndex &parent = QModelIndex()) const override;
    // 获取节点数据:包括DisplayRole|TextAlignmentRole等
    virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
};

实现几排几列表格情形的例子:

HistoryModel::HistoryModel(QObject *parent /*= 0*/)
    : QAbstractItemModel(parent)
{
}

QModelIndex HistoryModel::index(int row, int column, const QModelIndex &parent /*= QModelIndex()*/) const
{
    // 创建普通索引
    return createIndex(row, column);
}
QModelIndex HistoryModel::parent(const QModelIndex &child) const
{
    // 父节点均为跟节点
    return QModelIndex();
}
int HistoryModel::rowCount(const QModelIndex &parent /*= QModelIndex()*/) const
{
    // 根节点下有5行,其它行下没有
    if (parent.row() == -1)
    {
        return 5;
    }
    return 0;
}
int HistoryModel::columnCount(const QModelIndex &parent /*= QModelIndex()*/) const
{
    // 每行有量列
    return 2;
}

QVariant HistoryModel::data(const QModelIndex &index, int role /*= Qt::DisplayRole*/) const
{
    // 节点内容:左对齐,显示行列号
    if (role == Qt::TextAlignmentRole)
        return int(Qt::AlignLeft | Qt::AlignVCenter); 
    else if (role == Qt::DisplayRole) 
        return QString("row=%1,col=%2").arg(index.row()).arg(index.column());
    else
        return QVariant();
}

进一步使用,添加树形结构,自己构造树形结构数据:

struct NodeInfo
{
    QModelIndex parent;              // 父节点index
    QString sData;                   // 自身数据
    QVector<NodeInfo*> childNodes;   // 子节点
    int nRow;
    int nCol;
    NodeInfo(QModelIndex parentIdx, QString s, int row, int col):parent(parentIdx), sData(s), nRow(row), nCol(col){}
};

生成如下的这种界面:两个level=1节点,每个节点下有一些数据

可以这样来做:
每个节点存储一个NodeInfo信息,这样

  1. 每个节点可以查询子节点数量
  2. 每个节点可以查询到自身数据
  3. 可以根据NodeInfo信息(row/col/this)获取到QModeIndex
  4. 数据构造时,形成NodeInfo的树形层次
  5. QAbstractItemModel的接口中,index函数中绑定NodeInfo
  6. QAbstractItemModel的其它接口中,查询NodeInfo并使用
HistoryModel::HistoryModel(QObject *parent /*= 0*/)
    : QAbstractItemModel(parent)
{
    // 创建root节点
    m_pRootNode = new NodeInfo(nullptr, "rootNode", -1, -1);
    m_receiveInfo = new NodeInfo(m_pRootNode, "ReceiveMessage", 0, 0);
    m_replyInfo = new NodeInfo(m_pRootNode, "ReplyMessage", 1, 0);
    m_pRootNode->childNodes.append(m_receiveInfo);
    m_pRootNode->childNodes.append(m_replyInfo);
}

QModelIndex HistoryModel::index(int row, int column, const QModelIndex &parent /*= QModelIndex()*/) const
{
    if (parent.row() == -1 && parent.column() == -1)
    {
        // 首层节点绑定关系
        if (row < m_pRootNode->childNodes.count())
            return createIndex(row, column, m_pRootNode->childNodes[row]);
    }
    else
    {
        // 其它层节点绑定关系
        if (parent.internalPointer() != nullptr)
        {
            NodeInfo* pNode = reinterpret_cast<NodeInfo*>(parent.internalPointer());
            if (pNode->childNodes.size() > row)
            {
                return createIndex(row, column, pNode->childNodes[row]);
            } 
        }
    }
    return QModelIndex();
}

QModelIndex HistoryModel::parent(const QModelIndex &child) const
{
    if (child.internalPointer() != nullptr)
    {
        NodeInfo* pNode = reinterpret_cast<NodeInfo*>(child.internalPointer());
        NodeInfo* pParent = pNode->parent;
        if (pParent != nullptr)
        {
            // 根据父节点信息:row/col/node*获取Index
            return createIndex(pParent->nRow, pParent->nCol, pParent);;
        }
    }
    return QModelIndex();
}
int HistoryModel::rowCount(const QModelIndex &parent) const
{
    if (parent.internalPointer() == nullptr)
    {
        // 根节点下的数据行数
        return m_pRootNode->childNodes.count();
    }
    else
    {
        // 节点下的数据行数
        NodeInfo* pNode = reinterpret_cast<NodeInfo*>(parent.internalPointer());
        return pNode->childNodes.size();
    }
}
int HistoryModel::columnCount(const QModelIndex &parent /*= QModelIndex()*/) const
{
    // 每行有量列
    return 1;
}

QVariant HistoryModel::data(const QModelIndex &index, int role /*= Qt::DisplayRole*/) const
{
    // 节点内容:左对齐,显示行列号
    if (role == Qt::TextAlignmentRole)
    {
        return int(Qt::AlignLeft | Qt::AlignVCenter); 
    }
    else if (role == Qt::DisplayRole) 
    {
        if (index.internalPointer() == 0)
        {
            return QString("row=%1,col=%2").arg(index.row()).arg(index.column());
        }
        else
        {
            NodeInfo* pNode = reinterpret_cast<NodeInfo*>(index.internalPointer());
            return pNode->sData;
        }
    }
    else
    {
        return QVariant();
    }
}

(Owed by: 春夜喜雨 http://blog.csdn.net/chunyexiyu)

  • 12
    点赞
  • 56
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
QAbstractItemModelQt 框架中用于实现数据模型的抽象基类,它定义了一些纯虚函数,派生类需要实现这些函数来提供数据、索引、父子关系等信息。QTableView 是 Qt 框架中的一个表格控件,可以用于显示二维表格数据。 QTableView 需要一个 QAbstractItemModel 类型的数据模型来提供数据,因此一般的做法是通过继承 QAbstractItemModel 来实现自己的数据模型,然后将其与 QTableView 搭配使用。具体步骤如下: 1. 创建一个继承自 QAbstractItemModel 的类,实现其纯虚函数,提供数据、索引、父子关系等信息。 2. 在窗口中创建一个 QTableView 控件,并将其设置为自动填充整个窗口。 3. 创建自定义的数据模型实例,并将其设置给 QTableView 控件使用。 4. 将 QTableView 控件添加到窗口中,显示数据。 下面是一个简单的例子,演示了如何使用 QAbstractItemModelQTableView 显示一个二维表格数据: ``` python from PyQt5.QtCore import Qt, QAbstractTableModel, QModelIndex from PyQt5.QtWidgets import QApplication, QMainWindow, QTableView class MyModel(QAbstractTableModel): def __init__(self, data): super().__init__() self._data = data def rowCount(self, parent=QModelIndex()): return len(self._data) def columnCount(self, parent=QModelIndex()): return len(self._data[0]) def data(self, index, role=Qt.DisplayRole): if role == Qt.DisplayRole: return self._data[index.row()][index.column()] return None class MyWindow(QMainWindow): def __init__(self, data): super().__init__() self.setWindowTitle("My Window") self.setGeometry(100, 100, 400, 300) self.table_view = QTableView(self) self.table_model = MyModel(data) self.table_view.setModel(self.table_model) self.setCentralWidget(self.table_view) if __name__ == '__main__': app = QApplication([]) data = [ ["A1", "B1", "C1"], ["A2", "B2", "C2"], ["A3", "B3", "C3"] ] window = MyWindow(data) window.show() app.exec_() ``` 在这个例子中,我们创建了一个 MyModel 类来实现自己的数据模型,它继承自 QAbstractTableModel。在 MyModel 类中,我们实现了 rowCount、columnCount、data 等纯虚函数,提供了数据、行数和列数等信息。 在 MyWindow 类中,我们创建了一个 QTableView 控件,并将其设置为窗口的中心控件。然后,我们创建了自定义的数据模型实例并将其设置给 QTableView 控件使用。 最后,我们将 QTableView 控件添加到窗口中,显示数据。运行程序,可以看到一个简单的二维表格数据被显示出来了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

春夜喜雨

稀罕你的喜欢!!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值