Представление QML не будет обновляться при добавлении нового элемента в модель на основе QAbstractListModel

Я выяснил, как связать модель, полученную из QAbstractListModel, с представлением QML.

Но следующая вещь, которую я устал, не работает. Если в модель добавляется новый элемент, представление QML не будет обновляться. Это почему?

DataObject.h

class DataObject {
public:
DataObject(const QString &firstName,
const QString &lastName):
first(firstName),
last(lastName) {}

QString first;
QString last;
};

SimpleListModel.h

class SimpleListModel : public QAbstractListModel
{
Q_OBJECT

enum /*class*/ Roles {
FIRST_NAME = Qt::UserRole,
LAST_NAME
};

public:
SimpleListModel(QObject *parent=0);
QVariant data(const QModelIndex &index, int role) const;
Q_INVOKABLE int rowCount(const QModelIndex &parent = QModelIndex()) const;
QHash<int, QByteArray> roleNames() const;
void addName(QString firstName, QString lastName);

private:
Q_DISABLE_COPY(SimpleListModel);
QList<DataObject*> m_items;
};

SimpleListModel.cpp

SimpleListModel::SimpleListModel(QObject *parent) :
QAbstractListModel(parent)
{
DataObject *first = new DataObject(QString("Firstname01"), QString("Lastname01"));
DataObject *second = new DataObject(QString("Firstname02"), QString("Lastname02"));
DataObject *third = new DataObject(QString("Firstname03"), QString("Lastname03"));

m_items.append(first);
m_items.append(second);
m_items.append(third);
}

QHash<int, QByteArray> SimpleListModel::roleNames() const
{
QHash<int, QByteArray> roles;

roles[/*Roles::*/FIRST_NAME] = "firstName";
roles[/*Roles::*/LAST_NAME] = "lastName";

return roles;
}

void SimpleListModel::addName(QString firstName, QString lastName)
{
DataObject *dataObject = new DataObject(firstName, lastName);

m_items.append(dataObject);

emit dataChanged(this->index(m_items.size()), this->index(m_items.size()));
}

int SimpleListModel::rowCount(const QModelIndex &) const
{
return m_items.size();
}

QVariant SimpleListModel::data(const QModelIndex &index, int role) const
{
//--- Return Null variant if index is invalid
if(!index.isValid())
return QVariant();

//--- Check bounds
if(index.row() > (m_items.size() - 1))
return QVariant();

DataObject *dobj = m_items.at(index.row());

switch (role)
{
case /*Roles::*/FIRST_NAME:
return QVariant::fromValue(dobj->first);

case /*Roles::*/LAST_NAME:
return QVariant::fromValue(dobj->last);

default:
return QVariant();
}
}

AppCore.h

class AppCore : public QObject
{
Q_OBJECT
Q_PROPERTY(SimpleListModel *simpleListModel READ simpleListModel CONSTANT)

public:
explicit AppCore(QObject *parent = 0);
SimpleListModel *simpleListModel() const;

public slots:
void addName();

private:
SimpleListModel *m_SimpleListModel;

};

AppCore.cpp

AppCore::AppCore(QObject *parent) :
QObject(parent)
{
m_SimpleListModel = new SimpleListModel(this);
}

SimpleListModel *AppCore::simpleListModel() const
{
return m_SimpleListModel;
}

void AppCore::addName()
{
m_SimpleListModel->addName("FirstnameNEW", "LastnameNEW");
}

main.cpp

int main(int argc, char *argv[])
{
QGuiApplication a(argc, argv);

QQuickView *view = new QQuickView();
AppCore *appCore = new AppCore();

qRegisterMetaType<SimpleListModel *>("SimpleListModel");

view->engine()->rootContext()->setContextProperty("appCore", appCore);
view->setSource(QUrl::fromLocalFile("main.qml"));
view->show();

return a.exec();
}

main.qml

// ...
ListView {
id: myListView
anchors.fill: parent
delegate: myDelegate
model: appCore.simpleListModel
}

MouseArea {
anchors.fill: parent
onClicked: {
appCore.addName()
console.log('rowCount: ' + appCore.simpleListModel.rowCount())
}
}
//...

5

Решение

Вы должны вызывать beginInsertRows и endInsertRows вместо того, чтобы испускать сигнал

void SimpleListModel::addName(QString firstName, QString lastName)
{
DataObject *dataObject = new DataObject(firstName, lastName);

// tell QT what you will be doing
beginInsertRows(ModelIndex(),m_items.size(),m_items.size());

// do it
m_items.append(dataObject);

// tell QT you are done
endInsertRows();

}

эти 2 функции излучают все необходимые сигналы

11

Другие решения

Вы игнорируете семантику QAbstractItemModel, Существует два вида сигналов, которые модель должна излучать:

  • сигналы изменения данных: они должны излучаться после данные были изменены. Изменение данных — это изменение стоимости существующего элемента. Другие изменения в модели не называется изменение данных — терминология здесь имеет конкретное значение.

  • сигналы изменения структуры: они должны излучаться до а также после любые структурные изменения. Структурным изменением является добавление или удаление любого из элементов. beginXxxYyy а также endXxxYyy вспомогательные функции излучают эти сигналы.

1

По вопросам рекламы [email protected]