2014-02-17 6 views
5

Ich habe herausgefunden, wie man ein von QAbstractListModel abgeleitetes Modell an eine QML-Ansicht bindet.QML-Ansicht wird nicht aktualisiert, wenn ein neues Objekt einem QAbstractListModel-basierten Modell hinzugefügt wird

Aber das nächste, was ich müde, funktioniert nicht. Wenn ein neues Element zum Modell hinzugefügt wird, wird die QML-Ansicht nicht aktualisiert. Warum das?

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()) 
    } 
} 
//... 

Antwort

10

sollten Sie rufen beginInsertRows und endInsertRows statt Abstrahlen des Signals

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

} 

diese 2 Funktionen emittieren alle benötigten Signale

1

Sie die Semantik einer QAbstractItemModel ignorieren. Es gibt zwei Arten von Signalen, die ein Modell abgeben müssen:

  • Datenänderungs-Signale: Sie müssen nach die Daten geändert wurden emittiert werden. Eine Datenänderung ist eine Wertänderung eines vorhandenen Artikels. Andere Änderungen am Modell sind nicht genannt Datenänderungen - die Terminologie hat hier eine besondere Bedeutung.

  • Struktur Änderungssignale: Sie müssen vor und nach jede strukturelle Veränderung emittiert werden. Eine strukturelle Änderung ist das Hinzufügen oder Entfernen eines der Elemente. Die Hilfsfunktionen beginXxxYyy und endXxxYyy geben diese Signale aus.

Verwandte Themen