Qt QListView外部下拉列表不支持';行不通

Qt QListView外部下拉列表不支持';行不通,qt,drag-and-drop,qlistview,qsortfilterproxymodel,Qt,Drag And Drop,Qlistview,Qsortfilterproxymodel,我试图实现从一个QListView到另一个QListView的拖放项目(纯文本)。拖动开始得很好(我甚至可以将项目拖放到另一个接受文本拖放的应用程序),但我的第二个QListView由于某种原因不接受拖放。 以下是列表视图的配置方式: ui->lessonsListView->setAcceptDrops(true); ui->lessonsListView->setDropIndicatorShown(true); ui->lessonsListView->

我试图实现从一个QListView到另一个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;
}
代理模型代码:

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;
}
Qt::ItemFlags abonProxyModel::flags(常量QModelIndex&index)常量
{
返回Qt::ItemIsDragEnabled | QSortFilterProxyModel::flags(索引);
}
Qt::DropActions ABonProxyModel::supportedDragActions()常量
{

qDebug()我对代理模型没有太多经验。翻阅文档,我想我大致了解这两个函数是什么。这些函数不会自动调用。你必须从自己的角度“调用”它们

首先,检查您是否拥有正确的数据是模型的工作。因此,模型中有两个方便的函数可以简化您的工作。它们是特定于模型的函数,而不是泛型函数,因此从不为抽象模型定义

考虑这个场景。从某个地方将一个
QMimeData
对象拖放到您的视图中。您如何知道该数据是否属于正确的类型?谁来决定该数据是否属于正确的类型

模型视图
框架中,
视图
只进行绘制工作。由
模型
决定如何处理数据、显示什么、什么是可接受的,什么是不可接受的。因此,当在
视图
上删除一段数据时,您需要将其发送到
模型
以检查删除的数据是否正确ata满足
模型的要求。完成这项工作的钩子是
bool Model::canDropMimeData(…)

如果可以接受,那么数据的处理也需要由
模型本身来完成。同样,您需要将数据发送到
模型
。这方面的挂钩是
bool Model::dropMimeData(…)

如何知道数据处理是否成功?请检查返回值!如果数据处理成功,则很可能需要更新
视图

因此,除了上面的代码之外,还必须覆盖接收
视图的
dragEnterEvent
dragmovevent
dropEvent
,以便调用
candromimedata(…)
dropMimeData(…)


我终于找到了答案!当我开始编写这段代码时,我复制粘贴了Qt文档中的一些片段,而在本文中,它们只是错过了重新实现
candromimedata()
const
说明符。因此,我的版本是
candromimedata()
变成了非虚拟的,QListView只是从基类
QAbstractProxyModel
调用了该方法。我添加了
const
,所有这些都像一个没有任何子类的符咒一样工作。

我相信,您必须覆盖
QListView
DragentEvent
dropEvent
>子类。请看一下,谢谢!我会尝试。但是上面的文档说明:
此文档描述了基本的拖放机制,并概述了在自定义控件中启用该机制的方法。
我只是按照
下的说明,在项目视图中使用拖放功能。
链接也可以拖动工作对于没有任何子类的另一个列表视图,请注意:项目视图已经支持拖放。是的,拖放功能已经得到了完美的实现。但是拖放功能并没有达到预期的效果。我尝试使用
QListView
以及
QFileSystemModel
和文件浏览器(dolphin)进行简单的拖放实验。从
QListView
拖动到dolphin的效果非常好,但不接受相反的方式。因此,我相信,您必须为要执行拖放的小部件设置
DragentEvent
dragMoveEvent
dropEvent
。拖放到
QListView
效果很好,您不需要任何设置ubclasses.Show代码,您在其中配置启动拖动的
QListView
。我已经发布了“拖动端”代码。顺便说一句,我找到了Qt源代码,其功能类似于
candromimedata()
未在
QAbstractProxyModel
中声明
virtual
,因此调用了错误的函数:
QAbstractProxyModel::candromimedata()
而不是我的模型的
candromimedata()
。似乎这就是原因,但我不知道如何修复或解决它…似乎它只适用于
qabstractemmodel
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;
}
/* 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();
        }
    }
};