Bezdepbonusu7Программирование: статьи и ответы

Вопрос

Сортировка модели, производной от QAbstractListModel, по роли в QML ListView

Автор вопроса: dtechОтветов: 3

Я создал модель, производную от QAbstractListModel, на основе базового QHash. Поскольку мне нужно использовать модель в QML, я не могу использовать функции сортировки, интегрированные в виджеты и представления Qt.

Я пробовал использовать 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);

Увы, прокси работает как модель, но не сортирует записи.

qtqmlsortingqsortfilterproxymodelqabstractlistmodel

Ответы

Ответ 1 · рейтинг 6 · Raoul Hecky

Если вы включили QSortFilterProxyModel :: setDynamicSortFilter (true), вам нужно вызвать функцию QSortFilterProxyModel :: sort (...) один раз, чтобы позволить прокси-серверу знать, какой путь сортировать.

При этом каждый раз, когда модель обновляется, прокси будет снова сортировать все автоматически.

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

Ответ 2 · рейтинг 2 · Jan Kundrát

Во-первых, нет необходимости qobject_cast<QAbstractItemModel *> понижать значение - NewModel является производным классом от QAbstractItemModel, а принцип полиморфизма говорит, что вы можете использовать подкласс везде, где применим родительский класс.

Во-вторых, ваш prepend метод не использует beginInsertRows и endInsertRows. Это нарушение MVC API. Если вы будете использовать это таким образом, вы получите повреждение данных в прикрепленных представлениях и моделях прокси.

В-третьих, вы не упомянули, действительно ли вы используете свою прокси-модель в качестве модели для прикрепленного представления :).

Наконец, вы используете QHash в качестве резервного хранилища ваших данных с QHash::iterator для вставки. Это интересное решение, но то, что просто не может работать - вставка или удаление может привести к увеличению / уменьшению хэш-таблицы, что означает изменение всех данных, которые вы публикуете через свои модельные индексы. Это просто не сработает. Не используйте QHash, когда вам нужен стабильный заказ. O(n) сложность вашего delta метода следует интерпретировать как предупреждение; это неправильный подход.

Ответ 3 · Florian Schmidt

Взгляните на https://github.com/oKcerG/SortFilterProxyModel. Этот проект прекрасно раскрывает функциональность QSortFilterProxyModel для QML. Я использовал его в разных проектах, и он сработал. Однако, если вы хотите реализовать собственное решение, это поможет вам реализовать свои идеи.

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы