2022-10-10 Qt自定义Model时遇到的小坑

解决Qt QAbstractListModel中数据插入导致UI端显示异常的问题。通过调整beginInsertRows函数参数,避免UI端重复显示项。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题描述

自定义Qt的QAbstractListModel 模型,如下代码

class ArrowObject : public QObject {
    Q_OBJECT
    Q_PROPERTY(qreal heading READ heading WRITE setHeading NOTIFY headingChanged)
    Q_PROPERTY(QGeoCoordinate coord READ coord WRITE setCoord NOTIFY coordChanged)
public:
    ArrowObject()
    {
    }
    ArrowObject(const ArrowObject& other)
    {
        setHeading(other.heading());
        setCoord(other.coord());
    }
    ArrowObject(const qreal heading, const QGeoCoordinate& coord)
        : m_heading(heading)
        , m_coord(coord)
    {
    }

    qreal heading() const
    {
        return m_heading;
    }
    void setHeading(const qreal heading)
    {
        if (qFuzzyCompare(m_heading, heading))
            return;
        m_heading = heading;
        emit headingChanged();
    }
    QGeoCoordinate coord() const
    {
        return m_coord;
    }
    void setCoord(const QGeoCoordinate& coord)
    {
        if (!coord.isValid() || m_coord == coord)
            return;
        m_coord = coord;
        emit coordChanged();
    }

signals:
    void headingChanged();
    void coordChanged();

private:
    qreal          m_heading;
    QGeoCoordinate m_coord;
};
class ArrowModel : public QAbstractListModel {
    Q_OBJECT
    // QAbstractItemModel interface
public:
    ArrowModel()
    {
    }
    enum ArrowRoles { HeadingRole = Qt::UserRole + 1, CoordRole };
    int rowCount(const QModelIndex& parent = QModelIndex()) const override
    {
        return m_arrow.count();
    }
    QVariant data(const QModelIndex& index, int role) const override
    {
        if (!index.isValid())
            return QVariant();
        if (index.row() < 0 || index.row() >= m_arrow.count())
            return QVariant();
        const ArrowObject& arrow = m_arrow[index.row()];
        if (role == HeadingRole)
            return QVariant(arrow.heading());
        else if (role == CoordRole)
            return QVariant::fromValue(arrow.coord());
        return QVariant();
    }
    void appendArrow(const ArrowObject& arrow)
    {
        const int rowOfInsert = m_arrow.count();
        beginInsertRows(QModelIndex(), rowOfInsert, rowOfInsert+1);
        m_arrow.append(arrow);
        endInsertRows();
    }
    void clearArrow()
    {
        beginResetModel();
        m_arrow.clear();
        endResetModel();
    }

protected:
    // QAbstractItemModel interface
    QHash<int, QByteArray> roleNames() const override
    {
        static QHash<int, QByteArray> roles;
        roles[HeadingRole] = "heading";
        roles[CoordRole]   = "coord";
        return roles;
    }

private:
    QList<ArrowObject> m_arrow;
};

结果在UI端调用时出现问题了

    Repeater{
        model:arrows
        delegate: Item {
            Component.onCompleted: {
                console.log(coord,heading)
            }
        }   
    }

每个模型会多创建一个Item,也就是说本来模型里有10个数据,但Repeater 会打印20条数据


原因分析:

找了好半天才找出问题所在,问题出在 这句函数上,

beginInsertRows(QModelIndex(), rowOfInsert, rowOfInsert+1);

刚开始使用时就简单的理解为,添加一个数据,就做简单的数据偏移就可以了,但看完手册后才发现不是。

看手册说明:

在这里插入图片描述

手册里说到,first 应设置为添加数据前,数据应该添加的第一个位置,last为添加所有数据后,最后一个数据所在的位置。


我的代码里只添加一个元素,如果本来已有5条数据,那fist应该是5,添加完后,添加的那个元素所有位置为5,按我原来的代码,last为6了,模型认为我添加了两个数据,所以最后UI会多出一倍的数据。


吐槽一下,这个函数的设计思路好奇葩


解决方案:

代码改这样即可

beginInsertRows(QModelIndex(), rowOfInsert, rowOfInsert);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值