【问题标题】:QListView external drop doesn't workQListView 外部放置不起作用
【发布时间】:2016-03-28 19:54:12
【问题描述】:

我正在尝试将项目(纯/文本)从一个 QListView 拖放到另一个。拖动开始得很好(我什至可以将项目拖放到另一个接受文本拖放的应用程序),但我的第二个 QListView 出于某种原因不接受拖放。 以下是列表视图的配置方式:

ui->lessonsListView->setAcceptDrops(true);
ui->lessonsListView->setDropIndicatorShown(true);
ui->lessonsListView->setDragDropMode(QAbstractItemView::DropOnly);
ui->lessonsListView->setDragDropOverwriteMode(true);

此 listView 的代理模型实现以下方法:

Qt::ItemFlags LessonsProxyModel::flags(const QModelIndex &index) const
{
    qDebug() << __FUNCTION__;
    return Qt::ItemIsDropEnabled | QSortFilterProxyModel::flags(index);
}

Qt::DropActions LessonsProxyModel::supportedDropActions() const
{
    qDebug() << __FUNCTION__;
    return Qt::MoveAction;
}

bool LessonsProxyModel::canDropMimeData(const QMimeData *data,
    Qt::DropAction action, int row, int column, const QModelIndex &parent)
{
    qDebug() << __FUNCTION__;
    Q_UNUSED(action);
    Q_UNUSED(row);
    Q_UNUSED(column);

    if (!data->hasFormat("text/plain") || !parent.isValid())
        return false;

    return true;
}

bool LessonsProxyModel::dropMimeData(const QMimeData *data,
    Qt::DropAction action, int row, int column, const QModelIndex &parent)
{
    qDebug() << __FUNCTION__;
    if (!canDropMimeData(data, action, row, column, parent))
        return false;

    emit dataDropped(data, parent);

    return true;
}

从应用程序输出中,我看到只有 supportedDropActions()flags() 被调用。 canDropMimeData()dropMimeData() 都没有打过电话。我究竟做错了什么? 任何提示将不胜感激。

谢谢!

已编辑:

以防万一:下面是 listView 的源代码,并且从这些拖动中启动模型: 列表视图设置:

ui->abonsListView->setDragEnabled(true);

代理型号代码:

Qt::ItemFlags AbonsProxyModel::flags(const QModelIndex &index) const
{
    return Qt::ItemIsDragEnabled | QSortFilterProxyModel::flags(index);
}

Qt::DropActions AbonsProxyModel::supportedDragActions() const
{
    qDebug() << __FUNCTION__;
    return Qt::MoveAction;
}

QStringList AbonsProxyModel::mimeTypes() const
{
    qDebug() << __FUNCTION__;
    QStringList types;
    types << "text/plain";
    return types;
}

QMimeData *AbonsProxyModel::mimeData(const QModelIndexList &indexes) const
{
    qDebug() << __FUNCTION__;
    QMimeData *mimeData = new QMimeData();

    foreach (const QModelIndex &index, indexes)
        if (index.isValid())
        {
            mimeData->setText(data(index, AbonsModel::Id).toString());
            qDebug() << __FUNCTION__;
            return mimeData;
        }

    return mimeData;
}

【问题讨论】:

  • 我相信,您必须覆盖 QListView 子类的 dragEnterEventdragMoveEventdropEvent。看看documentationexamples
  • 谢谢!我会尝试。但上述文档指出:This document describes the basic drag and drop mechanism and outlines the approach used to enable it in custom controls. 而我只是按照Using drag and drop with item views 链接下的说明进行操作。对于另一个没有任何子类化的列表视图来说,拖动也很完美:项目视图已经支持拖放。
  • 是的,拖动完美实现。然而,下降没有按预期工作。我尝试使用QListView 加上QFileSystemModel 和文件浏览器(海豚)进行简单的拖放实验。从QListView 到 dolphin 的拖动效果非常好,但不接受反过来。所以我相信,你必须为你要执行放置的小部件设置dragEnterEventdragMoveEventdropEvent
  • Drop to QListView 工作正常,您不需要任何子类。显示代码,您在其中配置 QListView,开始拖动。
  • 我已经发布了“拖拽侧”的代码。顺便说一句,我发现 Qt 源代码,canDropMimeData() 之类的函数没有在QAbstractProxyModel 中声明virtual,并且由于这个错误的函数被调用:QAbstractProxyModel::canDropMimeData() 而不是我模型的canDropMimeData()。似乎这就是原因,但我不知道如何修复或解决它......似乎它只适用于QAbstractItemModel

标签: qt drag-and-drop qlistview qsortfilterproxymodel


【解决方案1】:

我终于找到答案了!当我开始编写这段代码时,我从 Qt 文档 Using Drag and Drop with Item Views 中复制粘贴了一些片段,而在本文中,他们只是错过了 const 重新实现 canDropMimeData() 的说明符。因此我的canDropMimeData() 版本变成了非虚拟的,QListView 只是从基类QAbstractProxyModel 中调用了该方法。我已经添加了const - 一切都像魅力一样工作,没有任何子类化。

【讨论】:

    【解决方案2】:

    我对代理模型没有太多经验。通过文档,我想我对这两个功能有一个粗略的了解。这些函数不会被自动调用。你必须从你的视野中“召唤”他们。

    首先,检查您是否拥有正确的数据是模型的工作。因此,这是模型中的两个便利功能,可简化您的工作。这些是特定于模型的函数,而不是通用函数,因此从未为抽象模型定义。

    考虑这种情况。从某处将QMimeData 对象拖放到您的视图中。你怎么知道这些数据的类型是否正确?决定数据是否属于正确类型的工作是谁的工作?

    Model-View 框架中,View 只做绘画工作。由Model 决定如何处理数据、显示什么、什么可以接受、什么不可以。所以当一条数据被丢弃在View 上时,您需要将它发送到Model 以检查丢弃的数据是否满足Model 的要求。完成这项工作的钩子是bool Model::canDropMimeData(...)

    如果可以接受,那么数据的处理也需要Model自己来完成。您需要再次将数据发送到Model。这个钩子是bool Model::dropMimeData(...)

    如何知道数据是否处理成功?检查返回值!如果数据处理成功,那么您很可能需要更新您的View

    因此,除了上面的代码之外,您必须覆盖接收方ViewdragEnterEventdragMoveEventdropEvent,以便您可以调用canDropMimeData(...)dropMimeData(...)

    /* You need to allow the drag to enter the widget/view. */
    /* This is a must. */
    void TargetView::dragEnterEvent( QDragEnterEvent *deEvent ) {
    
        deEvent->acceptProposedAction();
    };
    
    /* This is optional. Use this to check if the data can be */
    /* dropped at the current mouse position. Example: In a */
    /* FileSystem View, it makes no sense to drop a bunch of */
    /* files on top of a file, but makes sense it you drop it */
    /* in an empty space or on a folder */
    void TargetView::dragMoveEvent( QDragMoveEvent *dmEvent ) {
        /* You can do something like this */
        if ( indexAt( dmEvent->pos() ).isValid() ) {
            /* You cannot drop it on an existing index */
            /* If you ignore it, the cursor changes to */
            /* 'don't drop' image */
            dmEvent->ignore();
        }
    
        else {
            /* Empty space. Tell the user to feel free */
            /* to perform the drop. We accept the event */
            /* Cursor shows the drag+drop icon */
            dmEvent->accept();
        }
    };
    
    void TargetView::dropEvent( QDropEvent *dpEvent ) {
        /* Here is where you call canDropMimeData and dropMimeData */
        QMimeData *mData = dpEvent->mimeData();
        if ( model->canDropMimeData( mData, ..., ..., ..., ... ) ) {
            /* Add the data to the model */
            bool updated = model->dropMimeData( mData, ..., ..., ..., ... );
            if ( updated ) {
                /* Intimate the view to update itself */
                update();
            }
        }
    };
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-17
      • 2017-05-05
      • 2015-04-15
      • 2021-09-12
      • 2012-07-06
      • 2020-04-13
      相关资源
      最近更新 更多