我已经基于底层的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);
唉,代理作为一个模型,但它没有对条目进行排序。
答案 0 :(得分:6)
如果启用QSortFilterProxyModel :: setDynamicSortFilter(true),则需要调用一次QSortFilterProxyModel :: sort(...)函数,让代理知道要排序的方式。
有了这个,只要模型更新,代理就会自动对所有内容进行排序。
proxy.setDynamicSortFilter(true);
proxy.sort(0);
答案 1 :(得分:1)
首先,不需要qobject_cast<QAbstractItemModel *>
向下转换 - NewModel
是QAbstractItemModel
的派生类,而多态原则说你可以在任何地方使用子类父类是适用的。
其次,您的prepend
方法不使用beginInsertRows
和endInsertRows
。这违反了MVC API。如果您以这种方式使用它,您将在附加的视图和代理模型中获得数据损坏。
第三,您没有提到您是否实际使用代理模型作为附加视图的模型:)。
最后,您使用QHash
作为数据的后备存储,并QHash::iterator
进行插入。这是一个非常有用的解决方案,但是无法正常工作 - 插入或删除会导致哈希表增长/缩小,这意味着更改通过模型索引发布的所有数据。这是行不通的。需要稳定订单时,请勿使用QHash
。 O(n)
方法的delta
复杂性应该被解释为警告;这是一种错误的做法。
答案 2 :(得分:0)
看看https://github.com/oKcerG/SortFilterProxyModel。该项目向QML很好地公开了QSortFilterProxyModel的功能。我在不同的项目中使用了它,但后来却起作用了。但是,如果您想实施自己的解决方案,那么您就有了自己的想法。