当使用 QSortFilterProxyModel 对 QListView 进行过滤时,拖动顺序的改变通常不会生效,因为 QSortFilterProxyModel 是只读的,不支持修改模型中的数据顺序。要解决这个问题,可以通过以下方法实现:
- 操作源模型:在拖动和放置时,将操作应用于 QSortFilterProxyModel 的源模型 (sourceModel)。
- 自定义代理模型:重写 QSortFilterProxyModel 的方法以支持拖放和顺序修改。
下面提供一个完整的实现示例:
实现步骤
1. 自定义 QSortFilterProxyModel
我们需要重写 QSortFilterProxyModel 的 flags 和 moveRows 方法。
#include <QSortFilterProxyModel>
class CustomSortFilterProxyModel : public QSortFilterProxyModel {
Q_OBJECT
public:
explicit CustomSortFilterProxyModel(QObject *parent = nullptr)
: QSortFilterProxyModel(parent) {}
Qt::ItemFlags flags(const QModelIndex &index) const override {
if (!index.isValid())
return Qt::NoItemFlags;
// 保留拖动和放置的标志
return QSortFilterProxyModel::flags(index) | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled;
}
bool moveRows(const QModelIndex &sourceParent, int sourceRow, int count,
const QModelIndex &destinationParent, int destinationRow) override {
if (!sourceModel())
return false;
// 将操作映射到源模型
QModelIndex sourceStart = mapToSource(index(sourceRow, 0, sourceParent));
QModelIndex sourceEnd = mapToSource(index(sourceRow + count - 1, 0, sourceParent));
QModelIndex sourceDest = mapToSource(index(destinationRow, 0, destinationParent));
return sourceModel()->moveRows(sourceStart.parent(), sourceStart.row(), count,
sourceDest.parent(), sourceDest.row());
}
};
2. 主窗口代码
#include <QApplication>
#include <QListView>
#include <QStandardItemModel>
#include "CustomSortFilterProxyModel.h"
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
// 创建源模型
QStandardItemModel *sourceModel = new QStandardItemModel;
QStringList items = {"Item 1", "Item 2", "Item 3", "Item 4"};
for (const QString &itemText : items) {
QStandardItem *item = new QStandardItem(itemText);
item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled);
sourceModel->appendRow(item);
}
// 创建代理模型并设置过滤规则
CustomSortFilterProxyModel *proxyModel = new CustomSortFilterProxyModel;
proxyModel->setSourceModel(sourceModel);
proxyModel->setFilterRole(Qt::DisplayRole);
proxyModel->setFilterRegExp(QRegExp("Item [13]", Qt::CaseInsensitive)); // 仅显示 Item 1 和 Item 3
// 创建 QListView
QListView *listView = new QListView;
listView->setModel(proxyModel);
listView->setDragDropMode(QAbstractItemView::InternalMove);
listView->setDefaultDropAction(Qt::MoveAction);
listView->setDragEnabled(true);
listView->setAcceptDrops(true);
listView->setDropIndicatorShown(true);
listView->show();
return app.exec();
}
注意事项
- 源模型更新:拖放操作会更新源模型中的顺序,但只会影响过滤后的项在视图中的显示顺序。
- 数据同步:确保源模型和代理模型的数据状态同步,避免因过滤条件改变导致异常行为。