问题
I've figured out how to bind a model derived from QAbstractListModel to a QML view.
But the next thing I tired does not work. If a new Item is added to the model the QML view will not update. Why is that?
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())
}
}
//...
回答1:
you should call beginInsertRows
and endInsertRows
instead of emitting the signal
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();
}
these 2 functions emit all needed signals
回答2:
You're ignoring the semantics of a QAbstractItemModel
. There are two kinds of signals that a model must emit:
data change signals: They must be emitted after the data was changed. A data change is a change of value of an existing item. Other changes to the model are not called data changes - the terminology here has a specific meaning.
structure change signals: They must be emitted before and after any structural change. A structural change is addition or removal of any of the items. The
beginXxxYyy
andendXxxYyy
helper functions emit those signals.
来源:https://stackoverflow.com/questions/21829285/qml-view-wont-update-when-adding-a-new-item-to-a-qabstractlistmodel-based-model