问题描述
自定义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);