📄 qsortfilterproxymodel.cpp
字号:
the model to reorder the data in the model. To make your data sortable, you can either implement sort() in your model, or you use a QSortFilterProxyModel to wrap your model -- QSortFilterProxyModel provides a generic sort() reimplementation that operates on the Qt::DisplayRole of the items and that understands several data types, including \c int, QString, and QDateTime. For hierarchical models, sorting is applied recursively to all child items. String comparisons are case sensitive. Custom sorting behavior is achieved by subclassing QSortFilterProxyModel and reimplementing lessThan(), which is used to compare items. For example: \code bool MySortFilterProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const { QVariant leftData = sourceModel()->data(left); QVariant rightData = sourceModel()->data(right); if (leftData.type() == QVariant::DateTime) { return leftData.toDateTime() < rightData.toDateTime(); } else { return QString::localeAwareCompare(leftData.toString(), rightData.toString()) < 0; } } \endcode An alternative approach to sorting is to disable sorting on the view and to impose a certain order to the user. This is done by explicitly calling sort() with the desired column and order as arguments on the QSortFilterProxyModel (or on the original model if it implements sort()). For example: \code proxyModel->sort(2, Qt::AscendingOrder); \endcode The \l{itemviews/sortingmodel}{Sorting Model} example illustrates how to use QSortFilterProxyModel to perform basic sorting. \section1 Filtering In addition to sorting, QSortFilterProxyModel can be used to hide items that don't match a certain filter. The filter is specified using a QRegExp object and is applied to the Qt::DisplayRole of each item, for a given column. The QRegExp object can be used to match a regular expression, a wildcard pattern, or a fixed string. For example: \code proxyModel->setFilterRegExp(QRegExp(".png", Qt::CaseInsensitive, QRegExp::FixedString)); proxyModel->setFilterKeyColumn(1); \endcode For hierarchical models, the filter is applied recursively to all children. If a parent item doesn't match the filter, none of its children will be shown. Custom filtering behavior can be achieved by reimplementing the filterAcceptsRow() and filterAcceptsColumn() functions. For example, the following implementation ignores the \l filterKeyColumn property and performs filtering on columns 0, 1, and 2: \code bool MySortFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const { QModelIndex index0 = sourceModel()->index(sourceRow, 0, sourceParent); QModelIndex index1 = sourceModel()->index(sourceRow, 1, sourceParent); QModelIndex index2 = sourceModel()->index(sourceRow, 2, sourceParent); return (sourceModel()->data(index0).toString().contains(filterRegExp()) || sourceModel()->data(index1).toString().contains(filterRegExp())) && dateInRange(sourceModel()->data(index2).toDate()); } \endcode \sa QAbstractProxyModel, QAbstractItemModel, {Model/View Programming}*//*! Constructs a sorting filter model with the given \a parent.*/QSortFilterProxyModel::QSortFilterProxyModel(QObject *parent) : QAbstractProxyModel(*new QSortFilterProxyModelPrivate, parent){ Q_D(QSortFilterProxyModel); d->sort_column = -1; d->sort_order = Qt::AscendingOrder; d->filter_column = 0; connect(this, SIGNAL(modelReset()), this, SLOT(clear()));}/*! Destroys this sorting filter model.*/QSortFilterProxyModel::~QSortFilterProxyModel(){ Q_D(QSortFilterProxyModel); qDeleteAll(d->source_index_mapping); d->source_index_mapping.clear();}/*! \reimp*/void QSortFilterProxyModel::setSourceModel(QAbstractItemModel *sourceModel){ Q_D(QSortFilterProxyModel); if (d->model && d->model != &d->empty) { disconnect(d->model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(_q_sourceDataChanged(QModelIndex,QModelIndex))); disconnect(d->model, SIGNAL(headerDataChanged(Qt::Orientation,int,int)), this, SLOT(_q_sourceHeaderDataChanged(Qt::Orientation,int,int))); disconnect(d->model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)), this, SLOT(_q_sourceLayoutAboutToBeChanged(QModelIndex))); disconnect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(_q_sourceLayoutChanged())); disconnect(d->model, SIGNAL(columnsAboutToBeInserted(QModelIndex,int,int)), this, SLOT(_q_sourceLayoutAboutToBeChanged(QModelIndex))); disconnect(d->model, SIGNAL(columnsInserted(QModelIndex,int,int)), this, SLOT(_q_sourceLayoutChanged())); disconnect(d->model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)), this, SLOT(_q_sourceLayoutAboutToBeChanged(QModelIndex))); disconnect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SLOT(_q_sourceLayoutChanged())); disconnect(d->model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)), this, SLOT(_q_sourceLayoutAboutToBeChanged(QModelIndex))); disconnect(d->model, SIGNAL(columnsRemoved(QModelIndex,int,int)), this, SLOT(_q_sourceLayoutChanged())); disconnect(d->model, SIGNAL(modelReset()), this, SLOT(_q_sourceReset())); disconnect(d->model, SIGNAL(layoutChanged()), this, SLOT(clear())); } QAbstractProxyModel::setSourceModel(sourceModel); if (sourceModel) { connect(d->model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(_q_sourceDataChanged(QModelIndex,QModelIndex))); connect(d->model, SIGNAL(headerDataChanged(Qt::Orientation,int,int)), this, SLOT(_q_sourceHeaderDataChanged(Qt::Orientation,int,int))); connect(d->model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)), this, SLOT(_q_sourceLayoutAboutToBeChanged(QModelIndex))); connect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(_q_sourceLayoutChanged())); connect(d->model, SIGNAL(columnsAboutToBeInserted(QModelIndex,int,int)), this, SLOT(_q_sourceLayoutAboutToBeChanged(QModelIndex))); connect(d->model, SIGNAL(columnsAboutToBeInserted(QModelIndex,int,int)), this, SLOT(_q_sourceLayoutAboutToBeChanged(QModelIndex))); connect(d->model, SIGNAL(columnsInserted(QModelIndex,int,int)), this, SLOT(_q_sourceLayoutChanged())); connect(d->model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)), this, SLOT(_q_sourceLayoutAboutToBeChanged(QModelIndex))); connect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SLOT(_q_sourceLayoutChanged())); connect(d->model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)), this, SLOT(_q_sourceLayoutAboutToBeChanged(QModelIndex))); connect(d->model, SIGNAL(columnsRemoved(QModelIndex,int,int)), this, SLOT(_q_sourceLayoutChanged())); connect(d->model, SIGNAL(modelReset()), this, SLOT(_q_sourceReset())); connect(d->model, SIGNAL(layoutChanged()), this, SLOT(clear())); } d->clear_mapping(); reset();}/*! \reimp*/QModelIndex QSortFilterProxyModel::index(int row, int column, const QModelIndex &parent) const{ Q_D(const QSortFilterProxyModel); if (row < 0 || column < 0) return QModelIndex(); QModelIndex source_parent = d->proxy_to_source(parent); // parent is already mapped at this point IndexMap::const_iterator it = d->create_mapping(source_parent); // but make sure that the children are mapped if (it.value()->source_rows.count() <= row || it.value()->source_columns.count() <= column) return QModelIndex(); return d->create_index(row, column, it);}/*! \reimp*/QModelIndex QSortFilterProxyModel::parent(const QModelIndex &child) const{ if (!child.isValid()) return QModelIndex(); Q_D(const QSortFilterProxyModel); IndexMap::const_iterator it = d->index_to_iterator(child); Q_ASSERT(it != d->source_index_mapping.end()); QModelIndex source_parent = it.key(); QModelIndex proxy_parent = d->source_to_proxy(source_parent); return proxy_parent;}/*! \reimp*/int QSortFilterProxyModel::rowCount(const QModelIndex &parent) const{ Q_D(const QSortFilterProxyModel); QModelIndex source_parent = d->proxy_to_source(parent); IndexMap::const_iterator it = d->create_mapping(source_parent); return it.value()->source_rows.count();}/*! \reimp*/int QSortFilterProxyModel::columnCount(const QModelIndex &parent) const{ Q_D(const QSortFilterProxyModel); QModelIndex source_parent = d->proxy_to_source(parent); IndexMap::const_iterator it = d->create_mapping(source_parent); return it.value()->source_columns.count();}/*! \reimp*/bool QSortFilterProxyModel::hasChildren(const QModelIndex &parent) const{ Q_D(const QSortFilterProxyModel); QModelIndex source_parent = d->proxy_to_source(parent); if (!d->model->hasChildren(source_parent)) return false; QSortFilterProxyModelPrivate::Mapping *m = d->create_mapping(source_parent).value(); return m->source_rows.count() != 0 && m->source_columns.count() != 0;}/*! \reimp*/QVariant QSortFilterProxyModel::data(const QModelIndex &index, int role) const{ Q_D(const QSortFilterProxyModel); QModelIndex source_index = d->proxy_to_source(index); return d->model->data(source_index, role);}/*! \reimp*/bool QSortFilterProxyModel::setData(const QModelIndex &index, const QVariant &value, int role){ Q_D(QSortFilterProxyModel); QModelIndex source_index = d->proxy_to_source(index); return d->model->setData(source_index, value, role);}/*! \reimp*/QVariant QSortFilterProxyModel::headerData(int section, Qt::Orientation orientation, int role) const{ Q_D(const QSortFilterProxyModel); IndexMap::const_iterator it = d->create_mapping(QModelIndex()); int source_section; if (orientation == Qt::Vertical) { if (section < 0 || section >= it.value()->source_rows.count()) return QVariant(); source_section = it.value()->source_rows.at(section); } else { if (section < 0 || section >= it.value()->source_columns.count()) return QVariant(); source_section = it.value()->source_columns.at(section); } return d->model->headerData(source_section, orientation, role);}/*! \reimp*/bool QSortFilterProxyModel::setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role){ Q_D(QSortFilterProxyModel); IndexMap::const_iterator it = d->create_mapping(QModelIndex()); int source_section; if (orientation == Qt::Vertical) { if (section < 0 || section >= it.value()->source_rows.count()) return false; source_section = it.value()->source_rows.at(section); } else { if (section < 0 || section >= it.value()->source_columns.count()) return false; source_section = it.value()->source_columns.at(section); } return d->model->setHeaderData(source_section, orientation, value, role);}/*! \reimp*/QMimeData *QSortFilterProxyModel::mimeData(const QModelIndexList &indexes) const{ Q_D(const QSortFilterProxyModel); QModelIndexList source_indexes; for (int i = 0; i < indexes.count(); ++i) source_indexes << d->proxy_to_source(indexes.at(i)); return d->model->mimeData(source_indexes);}/*! \reimp*/bool QSortFilterProxyModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent){ Q_D(QSortFilterProxyModel); QModelIndex proxy_index = index(row, column, parent); QModelIndex source_index = d->proxy_to_source(proxy_index); return d->model->dropMimeData(data, action, source_index.row(), source_index.column(), source_index.parent());}/*! \reimp*/bool QSortFilterProxyModel::insertRows(int row, int count, const QModelIndex &parent){ Q_D(QSortFilterProxyModel); if (row < 0 || count <= 0) return false; QModelIndex source_parent = d->proxy_to_source(parent); QSortFilterProxyModelPrivate::Mapping *m = d->create_mapping(source_parent).value(); if (row > m->source_rows.count()) return false; int source_row = (row >= m->source_rows.count() ? m->source_rows.count() : m->source_rows.at(row)); return d->model->insertRows(source_row, count, source_parent);}/*! \reimp*/bool QSortFilterProxyModel::insertColumns(int column, int count, const QModelIndex &parent){ Q_D(QSortFilterProxyModel); if (column < 0|| count <= 0) return false; QModelIndex source_parent = d->proxy_to_source(parent); QSortFilterProxyModelPrivate::Mapping *m = d->create_mapping(source_parent).value(); if (column > m->source_columns.count()) return false;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -