在向基于QAbstractListModel的模型添加新项时,QML视图不会更新

时间:2014-02-17 12:35:19

标签: c++ qt qml qt-quick qabstractitemmodel

我已经想出如何将从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())
    }
}
//...

2 个答案:

答案 0 :(得分:11)

您应该拨打beginInsertRowsendInsertRows而不是发出信号

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();

}

这两个函数发出所有需要的信号

答案 1 :(得分:1)

你忽略了QAbstractItemModel的语义。模型必须发出两种信号:

  • 数据更改信号:数据更改后必须发出。数据更改是现有项的值的更改。对模型的其他更改是 not 称为数据更改 - 此处的术语具有特定含义。

  • 结构更改信号:必须在之前发出之后任何结构更改。结构变化是添加或删除任何项目。 beginXxxYyyendXxxYyy辅助函数会发出这些信号。