8

我创建了一个基于底层 QHash 的 QAbstractListModel 派生模型。由于我需要在 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);

唉,代理作为模型工作,但它不对条目进行排序。

4

3 回答 3

8

如果启用 QSortFilterProxyModel::setDynamicSortFilter(true),则需要调用一次 QSortFilterProxyModel::sort(...) 函数,让代理知道采用哪种方式排序。

这样,每当模型更新时,代理都会自动再次对所有内容进行排序。

proxy.setDynamicSortFilter(true);
proxy.sort(0);
于 2013-08-21T08:24:05.150 回答
2

首先,不需要qobject_cast<QAbstractItemModel *>向下转换——它NewModel是 the 的派生类,QAbstractItemModel并且多态性原则说,您可以在父类适用的任何地方使用子类。

其次,您的prepend方法不使用beginInsertRowsand endInsertRows。这违反了 MVC API。如果您以这种方式使用它,您将在附加的视图和代理模型中获得数据损坏。

第三,你没有提到你是否真的使用你的代理模型作为附加视图的模型:)。

最后,您将其用作插入QHash数据的后备存储。QHash::iterator这是一个非常有趣的解决方案,但有些东西是行不通的——插入或删除会导致哈希表增长/缩小,这意味着更改您通过模型索引发布的所有数据。这是行不通的。QHash当您需要稳定的订单时不要使用。您的方法的O(n)复杂性delta应被解释为警告;这是错误的做法。

于 2013-04-25T20:22:06.577 回答
0

看看https://github.com/oKcerG/SortFilterProxyModel。这个项目很好地向 QML 公开了 QSortFilterProxyModel 的功能。我在不同的项目中使用了它,它确实有效。但是,如果您想实施自己的解决方案,那么您的想法就很重要了。

于 2019-06-05T07:33:06.007 回答