首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >QTableView + QAbstractTableModel:通过拖放移动行

QTableView + QAbstractTableModel:通过拖放移动行
EN

Stack Overflow用户
提问于 2017-07-13 10:18:37
回答 2查看 4K关注 0票数 6

我有一个简单的QAbstractTableModel-based模型和一个QTableView

我的目标也很简单:允许通过拖放移动/重新排序行。备注:

  • QTableView内部的变化应该反映在我的模型中;
  • 被认为是内部运动,应该只在我的视野内进行,而不是外部的MIME出口;
  • 我想拖拽整排。不应拖放单独的物品;
  • 拖动水平标题对我来说不是一个合适的解决方案,因为我希望标题被隐藏,因为我想让用户在任何地方抓取行来拖动它;

我真的很接近我的目标。但它还是不像我预期的那样起作用。现在,我可以拖动行,但似乎任何单元格都可以接受下拉列表,尽管我只为全局表的父表指定了Qt::ItemIsDropEnabled,并且没有为实际的表项指定此标志,因为我不想拖到它们,我希望以某种方式删除“行之间”,只是为了执行行移动。由于表项由于某种原因可以接受滴落,所以我会有奇怪的行为:如果下降到任何行的第一个单元格,我就实现了我想要的结果:我的行正确移动。但是如果我跳到任何一行的非第一个单元格,它就完全错误了。但最好给我看看这里发生的事情:

我的代码(包含我的问题的最小示例):

main.cpp

代码语言:javascript
复制
void setupView(QTableView &t)
{
    t.verticalHeader()->hide();
    t.horizontalHeader()->hide();
    t.horizontalHeader()->setStretchLastSection(true);

    t.setSelectionBehavior(QAbstractItemView::SelectRows);
    t.setSelectionMode(QAbstractItemView::SingleSelection);

    t.setDragEnabled(true);
    t.setDropIndicatorShown(true);
    t.setAcceptDrops(true);
    t.viewport()->setAcceptDrops(true);
    t.setDefaultDropAction(Qt::MoveAction);
    t.setDragDropMode(QTableView::InternalMove);
    t.setDragDropOverwriteMode(false);
}

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QMainWindow w;

    QTableView *table = new QTableView(&w);
    setupView(*table);
    table->setModel(new TableModel);

    w.setCentralWidget(table);
    w.show();

    return a.exec();
}

tablemodel.cpp

代码语言:javascript
复制
#include "tablemodel.h"

TableModel::TableModel()
{
    // m_data is a QList<QStringList>
    m_data = {
        {"Name", "Kelly"},
        {"Age", "19"},
        {"Gender", "Female"},
    };
}

int TableModel::rowCount(const QModelIndex &parent) const {
    return m_data.size();
}

int TableModel::columnCount(const QModelIndex &parent) const {
    return 2;
}

QVariant TableModel::data(const QModelIndex &i, int r) const
{
    return (r == Qt::DisplayRole) ? m_data[i.row()][i.column()] : QVariant();
}

QVariant TableModel::headerData(int section, Qt::Orientation orientation, int r) const
{
    return QVariant();
}

Qt::ItemFlags TableModel::flags(const QModelIndex &index) const
{
    Qt::ItemFlags f = Qt::ItemIsEnabled | Qt::ItemIsSelectable
                    | Qt::ItemIsEditable | Qt::ItemIsDragEnabled;

    if(!index.isValid()) {
        f |= Qt::ItemIsDropEnabled;
    }

    return f;
}

Qt::DropActions TableModel::supportedDropActions() const
{
    return Qt::MoveAction | Qt::CopyAction;
}

bool TableModel::setData(const QModelIndex &i, const QVariant &v, int r)
{
    if(r == Qt::EditRole || r == Qt::DisplayRole) {
        m_data[i.row()][i.column()] = v.toString();
        return true;
    }
    return false;
}

bool TableModel::setItemData(const QModelIndex &i, const QMap<int, QVariant> &roles)
{
    if(!roles.contains(Qt::EditRole) && !roles.contains(Qt::DisplayRole)) {
        return false;
    }

    m_data[i.row()][i.column()] = roles[Qt::DisplayRole].toString();
    return true;
}

bool TableModel::insertRows(int row, int count, const QModelIndex &parent)
{
    beginInsertRows(QModelIndex(), row, row + count - 1);
    for(int i = 0; i<count; ++i) {
        m_data.insert(row, QStringList({"", ""}));
    }
    endInsertRows();
    return true;
}

bool TableModel::removeRows(int row, int count, const QModelIndex &parent)
{
    beginRemoveRows(QModelIndex(), row, row + count - 1);
    for(int i = 0; i<count; ++i) {
        m_data.removeAt(row);
    }
    endRemoveRows();
    return true;
}

bool TableModel::moveRows(const QModelIndex &srcParent, int srcRow, int count,
                          const QModelIndex &dstParent, int dstChild)
{
    beginMoveRows(QModelIndex(), srcRow, srcRow + count - 1, QModelIndex(), dstChild);
    for(int i = 0; i<count; ++i) {
        m_data.insert(dstChild + i, m_data[srcRow]);
        int removeIndex = dstChild > srcRow ? srcRow : srcRow+1;
        m_data.removeAt(removeIndex);
    }
    endMoveRows();
    return true;
}

请给我一些提示,模型或视图设置有什么问题。

UPD

对于那些对解决方案感兴趣的人:

代码语言:javascript
复制
bool TableModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent)
{
    Q_UNUSED(parent);
    Q_UNUSED(column);

    if(row == -1) {
        row = rowCount();
    }

    return QAbstractTableModel::dropMimeData(data, action, row, 0, parent);
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-07-13 11:48:39

您应该将dropMimeData方法添加到模型中,并正确地实现它。如果第一列上的下拉操作对您很好,那么您可能只需在模型的QAbstractItemModel::dropMimeData中调用column参数等于0的column参数,而不管实际在哪一列上执行。

票数 5
EN

Stack Overflow用户

发布于 2020-06-24 17:40:34

吹毛求疵:这两行没有必要:

代码语言:javascript
复制
t.setAcceptDrops(true);
t.viewport()->setAcceptDrops(true);
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/45077778

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档