You need to enable JavaScript to run this app. 如何实现QTableView拖拽调整行顺序并将更改同步到QSqlTableModel
优惠活动
大模型
产品
解决方案
定价
更多

如何实现QTableView拖拽调整行顺序并将更改同步到QSqlTableModel

解决Qt 5.15下QTableView拖拽调整行顺序并同步QSqlTableModel的方案

问题原因分析

  • 直接配置QTableView拖拽属性不生效:默认的QSqlTableModel没有返回Qt::ItemIsDragEnabled、Qt::ItemIsDropEnabled标记,视图层面不允许行拖拽操作
  • 垂直表头拖拽不同步:垂直表头的setSectionsMovable仅修改视图层的视觉展示顺序,不会修改底层模型的数据排序逻辑,模型刷新后就会恢复原始顺序

推荐实现方案(基于现有垂直表头拖拽改造,改动最小)

前置准备

你的数据库表需要新增一个INT类型的排序字段,例如命名为sort_seq,初始化时按现有行顺序依次赋值1、2、3...,用来持久化存储行的排序权重。

基础配置

保留你原来的垂直表头拖拽配置,额外加排序配置:

// 原有基础配置
ui->table_view->setSelectionMode(QAbstractItemView::SingleSelection);
ui->table_view->setSelectionBehavior(QAbstractItemView::SelectRows);
ui->table_view->setEditTriggers(QAbstractItemView::NoEditTriggers);

// 原有垂直表头拖拽配置
ui->table_view->verticalHeader()->setSectionsMovable(true);
ui->table_view->verticalHeader()->setDragEnabled(true);
ui->table_view->verticalHeader()->setDragDropMode(QAbstractItemView::InternalMove);
ui->table_view->verticalHeader()->setAcceptDrops(true);
// 新增配置:禁用表头自带排序,避免和我们自定义排序冲突
ui->table_view->verticalHeader()->setSortIndicatorShown(false);

// 模型配置:按sort_seq字段升序排序
int sortCol = model->fieldIndex("sort_seq");
model->setSort(sortCol, Qt::AscendingOrder);
model->select();

同步逻辑实现

绑定垂直表头的sectionMoved信号,在拖拽结束后自动同步排序到底层模型和数据库:

connect(ui->table_view->verticalHeader(), &QHeaderView::sectionMoved, this, [=](int logicalIndex, int oldVisualIndex, int newVisualIndex){
    // 临时屏蔽信号,避免修改模型时循环触发视图更新
    ui->table_view->verticalHeader()->blockSignals(true);
    int sortCol = model->fieldIndex("sort_seq");

    if (newVisualIndex > oldVisualIndex) {
        // 向下拖动:中间行排序值全部减1
        for (int i = oldVisualIndex; i < newVisualIndex; ++i) {
            int curSeq = model->index(i, sortCol).data().toInt();
            model->setData(model->index(i, sortCol), curSeq - 1);
        }
        // 设置被拖动行的新排序值
        model->setData(model->index(oldVisualIndex, sortCol), newVisualIndex + 1);
    } else {
        // 向上拖动:中间行排序值全部加1
        for (int i = newVisualIndex; i < oldVisualIndex; ++i) {
            int curSeq = model->index(i, sortCol).data().toInt();
            model->setData(model->index(i, sortCol), curSeq + 1);
        }
        // 设置被拖动行的新排序值
        model->setData(model->index(oldVisualIndex, sortCol), newVisualIndex + 1);
    }

    // 提交修改到数据库
    model->submitAll();
    // 刷新模型同步视图显示
    model->select();
    // 恢复信号接收
    ui->table_view->verticalHeader()->blockSignals(false);
});

可选方案:直接拖拽行调整顺序(无需拖表头)

如果需要点击行任意位置拖拽调整,需要自定义QSqlTableModel子类,开放拖拽权限并处理drop逻辑:

自定义模型代码

class CustomSqlModel : public QSqlTableModel {
    Q_OBJECT
public:
    CustomSqlModel(QObject *parent = nullptr, QSqlDatabase db = QSqlDatabase()) : QSqlTableModel(parent, db) {}

    // 开放拖拽、放置权限
    Qt::ItemFlags flags(const QModelIndex &index) const override {
        Qt::ItemFlags defaultFlags = QSqlTableModel::flags(index);
        if (index.isValid()) return defaultFlags | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled;
        return defaultFlags | Qt::ItemIsDropEnabled;
    }

    QStringList mimeTypes() const override {
        return {"application/x-qabstractitemmodeldatalist"};
    }

    Qt::DropActions supportedDropActions() const override {
        return Qt::MoveAction;
    }

    bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override {
        if (action == Qt::IgnoreAction) return true;
        if (!data->hasFormat("application/x-qabstractitemmodeldatalist") || column > 0) return false;

        // 解析源行索引
        int sourceRow;
        QByteArray encoded = data->data("application/x-qabstractitemmodeldatalist");
        QDataStream stream(&encoded, QIODevice::ReadOnly);
        stream >> sourceRow;

        // 计算目标行索引
        int destRow = parent.isValid() ? parent.row() : row;
        if (destRow < 0) destRow = rowCount() - 1;
        if (destRow == sourceRow) return true;

        // 这里复用上面的排序字段调整逻辑,修改对应行的sort_seq值后提交刷新即可
        int sortCol = fieldIndex("sort_seq");
        // 排序值调整逻辑和上面的sectionMoved槽函数完全一致,此处不再重复
        submitAll();
        select();
        return true;
    }
};

视图配置

ui->table_view->setDragEnabled(true);
ui->table_view->setAcceptDrops(true);
ui->table_view->setDropIndicatorShown(true);
ui->table_view->setDragDropMode(QAbstractItemView::InternalMove);

内容的提问来源于stack exchange,提问作者Ginakira

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.14 21:54:06