Qt QListView外部下拉列表不支持';行不通
我试图实现从一个QListView到另一个QListView的拖放项目(纯文本)。拖动开始得很好(我甚至可以将项目拖放到另一个接受文本拖放的应用程序),但我的第二个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->
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();
}
}
};