2013-04-25 23 views
6

Ich habe ein von QAbstractListModel abgeleitetes Modell erstellt, das auf einem zugrunde liegenden QHash basiert. Da ich das Modell in QML verwenden muss, kann ich nicht die Sortierfunktion nutzen, die Qt Widgets und Ansichten integriert haben.Sortieren eines von QAbstractListModel abgeleiteten Modells nach Rolle in QML ListView

Ich habe versucht, ein QSortFilterProxyModel, aber es scheint nicht mit meinem Modell zu arbeiten. Das Modell in QML richtig arbeiten zu lassen, war nicht mühsam genug, und jetzt bin ich beim Sortieren fest.

Alle Vorschläge sind willkommen.

Hier ist das Modell Quelle:

typedef QHash<QString, uint> Data; 

class NewModel : public QAbstractListModel { 
    Q_OBJECT 
    Q_PROPERTY(int count READ count NOTIFY countChanged) 

public: 
    NewModel(QObject * parent = 0) : QAbstractListModel(parent) {} 

    enum Roles {WordRole = Qt::UserRole, CountRole}; 

    QHash<int, QByteArray> roleNames() const { 
     QHash<int, QByteArray> roles; 
     roles[WordRole] = "word"; 
     roles[CountRole] = "count"; 
     return roles; 
    } 

    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const { 
     if (index.row() < 0 || index.row() >= m_data.size()) return QVariant(); 
     Data::const_iterator iter = m_data.constBegin() + index.row(); 

     switch (role) { 
     case WordRole: 
      return iter.key(); 
     case CountRole: 
      return iter.value(); 
     } return QVariant(); 
    } 

    int rowCount(const QModelIndex &parent) const { 
     Q_UNUSED(parent) 
     return m_data.size(); 
    } 

    int count() const { return m_data.size(); } 

public slots: 
    void append(const QString &word) { 
     bool alreadyThere = m_data.contains(word); 
     if (alreadyThere) m_data[word]++; 
     else m_data.insert(word, 1); 

     Data::const_iterator iter = m_data.find(word); 
     uint position = delta(iter); 

     if (alreadyThere) { 
      QModelIndex index = createIndex(position, 0); 
      emit dataChanged(index, index); 
     } else { 
      beginInsertRows(QModelIndex(), position, position); 
      endInsertRows(); 
      emit countChanged(); 
     } 
    } 

    void prepend(const QString &word) { 
     if (m_data.contains(word)) m_data[word]++; 
     else m_data.insert(word, 1); 
    } 

signals: 
    void countChanged(); 

private: 
    uint delta(Data::const_iterator i) { 
     uint d = 0; 
     while (i != m_data.constBegin()) { ++d; --i; } 
     return d; 
    } 

    Data m_data; 
}; 

hier, um es „versucht“ zu sortieren:

NewModel model; 
QAbstractItemModel * pm = qobject_cast<QAbstractItemModel *>(&model); 
QSortFilterProxyModel proxy; 
proxy.setSourceModel(pm); 
proxy.setSortRole(NewModel::WordRole); 
proxy.setDynamicSortFilter(true); 

Ach, arbeitet der Proxy als Modell, aber es sortieren nicht die Einträge .

Antwort

1

Zunächst einmal gibt es keine Notwendigkeit für qobject_cast<QAbstractItemModel *> Downcasting - die NewModel ist eine abgeleitete Klasse der QAbstractItemModel und das Polymorphismus Prinzip besagt, dass Sie eine Unterklasse überall nutzen können, wo eine übergeordnete Klasse anwendbar ist.

Zweitens verwendet Ihre prepend Methode nicht beginInsertRows und endInsertRows. Das ist eine Verletzung der MVC-API. In den angehängten Sichten und Proxy-Modellen erhalten Sie eine Datenbeschädigung, wenn Sie diese auf diese Weise verwenden.

Drittens haben Sie nicht erwähnt, ob Sie Ihr Proxy-Modell tatsächlich als Modell für die angehängte Ansicht verwenden :).

Schließlich verwenden Sie QHash als Backing-Speicher Ihrer Daten mit QHash::iterator zum Einfügen. Das ist eine interessante Lösung, aber etwas, das einfach nicht funktionieren kann - ein Einfügen oder Entfernen kann dazu führen, dass die Hash-Tabelle wächst/schrumpft, was bedeutet, dass alle Daten geändert werden, die Sie über Ihre Modellindizes veröffentlichen. Das wird einfach nicht funktionieren. Verwenden Sie nicht QHash, wenn Sie eine stabile Bestellung benötigen. Die O(n) Komplexität Ihrer delta Methode sollte als Warnung interpretiert werden; Das ist ein falscher Ansatz.

+0

'prepend()' wird verwendet, um das Modell zu füllen, wenn es nicht verwendet wird, es gibt kein Problem, es mit Bedacht zu verwenden. Ich muss QHash für die Suche verwenden, ich habe das bereits getan, indem ich den Hash für den Speicher verwendet habe und dann die Daten an ein anderes Modell übergebe, aber ich suche nach Möglichkeiten, die ursprünglichen Daten aus dem Hash wiederzuverwenden. Das Modell, so wie es aussieht, scheint in Ordnung zu sein, mein Problem ist nur beim Sortieren. – dtech

+1

Versuchen Sie, den ModelTest über Ihrem Code auszuführen, Sie könnten ziemlich überrascht sein. –

+0

Es wird in einem eng spezifizierten Kontext verwendet, der Gedanke, dass es als Teil der gesamten API perfekt ist, ist weit entfernt, ich ziele nur auf Funktionalität ab, die ich besonders brauche. Vielleicht funktioniert es deshalb nicht mit dem Sortier-Proxy. Es wird einfacher sein, meinen eigenen Sortier-Proxy-Wrapper zu erstellen, als den Bestand mit dem Modell zu arbeiten, während der zugrunde liegende Container für die schnellste Suche optimiert wird, was die N1-Anforderung ist. – dtech

6

Wenn Sie QSortFilterProxyModel :: setDynamicSortFilter (true) aktivieren, müssen Sie die Funktion QSortFilterProxyModel :: sort (...) einmal aufrufen, damit der Proxy weiß, welche Art zu sortieren ist.

Damit wird jedes Mal, wenn das Modell aktualisiert wird der Proxy alles wieder automatisch sortieren.

proxy.setDynamicSortFilter(true); 
proxy.sort(0); 
+0

Das funktioniert, danke! – Sharm