2013-04-25 28 views
6

Tôi đã tạo mô hình có nguồn gốc QAbstractListModel dựa trên một QHash cơ bản. Vì tôi cần sử dụng mô hình trong QML, tôi không thể sử dụng chức năng sắp xếp các widget và khung nhìn Qt đã tích hợp.Sắp xếp mô hình bắt nguồn QAbstractListModel theo vai trò trong QML ListView

Tôi đã thử sử dụng QSortFilterProxyModel nhưng có vẻ như nó không hoạt động với mô hình của tôi. Bắt mô hình làm việc đúng cách trong QML không đủ tẻ nhạt, và bây giờ tôi đang bị mắc kẹt khi phân loại.

Mọi đề xuất đều được đánh giá cao.

Đây là nguồn mô hình:

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

Dưới đây là "cố gắng" để sắp xếp nó:

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

Alas, proxy hoạt động như một người mẫu, nhưng nó không sắp xếp các mục .

Trả lời

1

Trước hết, Không cần cho qobject_cast<QAbstractItemModel *> downcasting - các NewModel là một lớp dẫn xuất của QAbstractItemModel và nguyên tắc đa hình nói rằng bạn có thể sử dụng một lớp con ở khắp mọi nơi mà một lớp cha mẹ có thể áp dụng.

Thứ hai, phương thức prepend của bạn không sử dụng beginInsertRowsendInsertRows. Đó là sự vi phạm API MVC. Bạn sẽ bị hỏng dữ liệu trong các kiểu xem và proxy được đính kèm nếu bạn sử dụng nó theo cách này.

Thứ ba, bạn chưa đề cập liệu bạn có đang sử dụng mô hình proxy làm mô hình cho chế độ xem được đính kèm :) hay không.

Cuối cùng, bạn đang sử dụng QHash làm cửa hàng sao lưu dữ liệu của mình với QHash::iterator để chèn. Đó là một giải pháp thích hợp, nhưng một thứ không thể hoạt động được - việc chèn hoặc loại bỏ có thể khiến bảng băm tăng/thu nhỏ, có nghĩa là thay đổi tất cả dữ liệu bạn xuất bản qua các chỉ mục mô hình của bạn. Điều này sẽ không hoạt động. Không sử dụng QHash khi bạn cần một thứ tự ổn định. Sự phức tạp O(n) của phương pháp delta của bạn sẽ được hiểu là cảnh báo; đây là một cách tiếp cận sai lầm.

+0

'prepend()' được sử dụng để điền vào mô hình khi không sử dụng, không có vấn đề gì khi sử dụng nó một cách khôn ngoan. Tôi cần sử dụng QHash để tra cứu, tôi đã thực hiện việc này bằng cách sử dụng băm để lưu trữ và sau đó chuyển dữ liệu sang một mô hình khác, nhưng tôi đang tìm cách sử dụng lại dữ liệu gốc từ băm. Các mô hình như nó xuất hiện để làm việc OK, vấn đề của tôi là chỉ với phân loại. – dtech

+1

Cố gắng chạy ModelTest trên đầu mã của bạn, bạn có thể khá ngạc nhiên. –

+0

Nó được sử dụng trong một bối cảnh được chỉ định chặt chẽ, ý nghĩ rằng nó hoàn hảo như là một phần của toàn bộ API bị loại bỏ xa, tôi chỉ nhắm đến chức năng tôi cần đặc biệt. Có lẽ đó là lý do tại sao nó không hoạt động với proxy sắp xếp. Sẽ dễ dàng hơn khi thực hiện trình bao bọc proxy sắp xếp của riêng tôi hơn để làm cho gói chứng khoán hoạt động với mô hình trong khi vẫn giữ vùng chứa bên dưới được tối ưu hóa để tra cứu nhanh nhất, đó là yêu cầu N1. – dtech

6

Nếu bạn bật QSortFilterProxyModel :: setDynamicSortFilter (true), bạn cần gọi hàm QSortFilterProxyModel :: sort (...) một lần để cho proxy biết cách sắp xếp.

Với điều đó, bất kỳ khi nào mô hình được cập nhật, proxy sẽ sắp xếp lại mọi thứ một cách tự động.

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

Công trình này, cảm ơn! – Sharm