2013-04-25 23 views
6

我已經基於基礎QHash創建了QAbstractListModel派生模型。由於我需要在QML中使用模型,因此我無法利用Qt窗口小部件和視圖集成的排序功能。按QML中的角色對QAbstractListModel派生模型進行排序ListView

我試過使用QSortFilterProxyModel,但它似乎不適用於我的模型。讓模型在QML中正常工作並不夠繁瑣,現在我一直在排序。

任何建議表示讚賞。

這裏是模型來源:

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; 
}; 

這裏的「嘗試」對它進行排序:

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

唉,代理工作作爲一種模式,但它不排序條目。

回答

1

首先,不需要qobject_cast<QAbstractItemModel *>向下轉換 - NewModelQAbstractItemModel的派生類,多態原則表示可以在任何可以使用父類的地方使用子類。

二,您的prepend方法不使用beginInsertRowsendInsertRows。這違反了MVC API。如果以這種方式使用,您將在附加的視圖和代理模型中獲得數據損壞。

第三,你還沒有提到你是否真的使用你的代理模型作爲附加視圖的模型:)。

最後,您使用QHash作爲數據的後備存儲,用於插入QHash::iterator。這是一個非常有用的解決方案,但是卻無法正常工作 - 插入或刪除操作會導致哈希表的增大/縮小,這意味着需要通過模型索引更改所有發佈的數據。這不會起作用。當您需要穩定的訂單時,請勿使用QHashdelta方法的複雜性應該被解釋爲警告;這是一個錯誤的方法。

+0

'prepend()'用於在不使用模型時填充模型,明智地使用它沒有問題。我需要使用QHash進行查找,我已經通過使用散列進行存儲並將數據傳輸到另一個模型來完成此操作,但我正在尋找從哈希中重用原始數據的方法。模型,因爲它似乎工作正常,我的問題只是與排序。 – dtech 2013-04-25 20:27:51

+1

試着在你的代碼上運行ModelTest,你可能會感到很驚訝。 – 2013-04-26 12:38:25

+0

它被用在一個嚴格規定的上下文中,認爲它作爲整個API的一部分是完美的,但它只是針對我特別需要的功能。也許這就是爲什麼它不適用於排序代理。做我自己的排序代理包裝比讓股票和模型一起工作容易,同時保持底層容器爲最快的查找而優化,這是N1的要求。 – dtech 2013-04-26 13:56:17

6

如果啓用QSortFilterProxyModel :: setDynamicSortFilter(true),則需要調用QSortFilterProxyModel :: sort(...)函數一次,以讓代理知道哪種方式進行排序。因此,無論何時更新模型,代理服務器都會自動對所有內容進行排序。

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

這個作品,謝謝! – Sharm 2018-01-20 23:12:25

相關問題