QListView 外部放置不起作用
QListView external drop doesn't work
我正在尝试实现从一个 QListView 到另一个 QListView 的拖放项目 (plain/text)。拖动开始很好(我什至能够将项目拖放到另一个接受文本拖放的应用程序),但我的第二个 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;
}
我对代理模型的经验不多。通过文档,我想我对这两个功能是什么有一个大概的了解。这些函数不会自动调用。你必须 "call" 从你的角度来看它们。
首先,检查您是否拥有正确的数据是模型的工作。因此,这是模型中的两个便利功能,可以简化您的工作。这些是特定于模型的函数而不是通用函数,因此永远不会为抽象模型定义。
考虑这个场景。从某个地方,一个 QMimeData
对象被放入您的视图中。您如何知道此数据的类型是否正确?由谁来决定数据的类型是否正确?
在Model-View
框架中,View
只做绘画工作。由 Model
决定诸如如何处理数据、显示什么、什么是可以接受的以及什么不是。所以当在 View
上丢了一个数据,你需要将它发送到 Model
来检查丢下的数据是否满足 Model
的要求。完成这项工作的钩子是 bool Model::canDropMimeData(...)
.
如果可以接受,那么数据的处理也需要Model
自己完成。同样,您需要将数据发送到 Model
。钩子是 bool Model::dropMimeData(...)
.
如何知道数据是否处理成功?检查 return 值!如果数据处理成功,那么您很可能需要更新 View
.
因此,除了上面的代码之外,您必须 覆盖接收 dragEnterEvent
、dragMoveEvent
和 dropEvent
View
这样你就可以调用 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();
}
}
};
我终于找到答案了!当我开始编写这段代码时,我从 Qt 文档 Using Drag and Drop with Item Views 中复制粘贴了一些片段,在这篇文章中,他们只是错过了 const
说明符以重新实现 canDropMimeData()
。因此,我的 canDropMimeData()
版本变成了非虚拟的,而 QListView 只是从基础 class QAbstractProxyModel
调用了方法。我添加了 const
- 没有任何子 classing,一切都像魅力一样工作。
我正在尝试实现从一个 QListView 到另一个 QListView 的拖放项目 (plain/text)。拖动开始很好(我什至能够将项目拖放到另一个接受文本拖放的应用程序),但我的第二个 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;
}
我对代理模型的经验不多。通过文档,我想我对这两个功能是什么有一个大概的了解。这些函数不会自动调用。你必须 "call" 从你的角度来看它们。
首先,检查您是否拥有正确的数据是模型的工作。因此,这是模型中的两个便利功能,可以简化您的工作。这些是特定于模型的函数而不是通用函数,因此永远不会为抽象模型定义。
考虑这个场景。从某个地方,一个 QMimeData
对象被放入您的视图中。您如何知道此数据的类型是否正确?由谁来决定数据的类型是否正确?
在Model-View
框架中,View
只做绘画工作。由 Model
决定诸如如何处理数据、显示什么、什么是可以接受的以及什么不是。所以当在 View
上丢了一个数据,你需要将它发送到 Model
来检查丢下的数据是否满足 Model
的要求。完成这项工作的钩子是 bool Model::canDropMimeData(...)
.
如果可以接受,那么数据的处理也需要Model
自己完成。同样,您需要将数据发送到 Model
。钩子是 bool Model::dropMimeData(...)
.
如何知道数据是否处理成功?检查 return 值!如果数据处理成功,那么您很可能需要更新 View
.
因此,除了上面的代码之外,您必须 覆盖接收 dragEnterEvent
、dragMoveEvent
和 dropEvent
View
这样你就可以调用 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();
}
}
};
我终于找到答案了!当我开始编写这段代码时,我从 Qt 文档 Using Drag and Drop with Item Views 中复制粘贴了一些片段,在这篇文章中,他们只是错过了 const
说明符以重新实现 canDropMimeData()
。因此,我的 canDropMimeData()
版本变成了非虚拟的,而 QListView 只是从基础 class QAbstractProxyModel
调用了方法。我添加了 const
- 没有任何子 classing,一切都像魅力一样工作。