2013-04-25 3 views
6

기본 QHash를 기반으로 QAbstractListModel 파생 모델을 만들었습니다. QML에서 모델을 사용해야하기 때문에 정렬 기능인 Qt 위젯과 뷰를 통합 할 수 없습니다.QAbstractListModel에서 파생 된 모델을 QML ListView에서 역할별로 정렬합니다.

QSortFilterProxyModel을 사용해 보았지만 내 모델에서는 작동하지 않습니다. 모델을 QML에서 제대로 작동하게하는 것은 지루한 작업이 아니 었습니다. 이제는 정렬 작업이 필요합니다.

모든 의견을 환영합니다. 여기

모델 소스입니다 :

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

아아, 프록시가 모델로 작동하지만,이 항목을 정렬하지 않습니다 여기에

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

는 "시도"입니다을 정렬하려면 . 모든

답변

1

첫째, qobject_cast<QAbstractItemModel *> downcasting에 대한 필요가 없습니다 - NewModelQAbstractItemModel의 파생 클래스이며, 다형성의 원리는 부모 클래스가 적용 위치를 어디서나 서브 클래스를 사용할 수 있다고 말한다.

두 번째로 prepend 메서드는 beginInsertRowsendInsertRows을 사용하지 않습니다. 이는 MVC API를 위반 한 것입니다. 이런 식으로 사용하면 연결된 뷰와 프록시 모델에서 데이터가 손상됩니다.

셋째로, 실제로 프록시 모델을 첨부 된 뷰의 모델로 사용하고 있는지 여부는 언급하지 않았습니다.

마지막으로 QHash을 데이터의 보조 저장소로 사용하여 삽입하려면 QHash::iterator입니다. 이는 흥미로운 솔루션이지만 작동하지 않는 항목 - 삽입 또는 제거로 인해 해시 테이블이 커지거나 줄어들 수 있습니다. 이는 모델 인덱스를 통해 게시하는 모든 데이터를 변경한다는 것을 의미합니다. 이것은 단지 작동하지 않을 것입니다. 안정적인 주문이 필요한 경우 QHash을 사용하지 마십시오. O(n)delta 메서드의 복잡성은 경고로 해석되어야합니다. 이것은 잘못된 접근입니다.

+0

'prepend()'는 사용하지 않을 때 모델을 채우는 데 사용됩니다. 현명한 사용에는 문제가 없습니다. 조회를 위해 QHash를 사용해야합니다. 이미 저장을 위해 해시를 사용하고 다른 모델로 데이터를 전송하여이 작업을 수행했습니다. 그러나 해시에서 원래 데이터를 다시 사용할 수있는 방법을 찾고 있습니다. 모델이 제대로 작동하는 것으로 보입니다. 문제는 정렬에만 있습니다. – dtech

+1

코드 상단에서 ModelTest를 실행하면 다소 놀랄 수 있습니다. –

+0

완전히 밀접하게 지정된 컨텍스트에서 사용되며, 전체 API의 일부로 완벽하다는 생각은 멀리 떨어져 있습니다. 특히 필요한 기능 만 겨냥합니다. 아마 그것이 정렬 프록시와 함께 작동하지 않는 이유 일 수 있습니다. 기본 컨테이너를 N1 요구 사항 인 가장 빠른 조회에 최적화 된 상태로 유지하면서 모델을 사용하여 재고 작업을 수행하는 것보다 자체 정렬 프록시 래퍼를 수행하는 것이 더 쉬울 것입니다. – dtech

6

QSortFilterProxyModel :: setDynamicSortFilter (true)를 활성화하면 QSortFilterProxyModel :: sort (...) 함수를 한 번 호출해야 프록시가 정렬 할 방법을 알 수 있습니다.

그러면 모델이 업데이트 될 때마다 프록시가 자동으로 모든 것을 다시 정렬합니다.

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

감사합니다. – Sharm