拖放操作分为拖动(Drag)和放置(Drop)两种操作,当拖动时需要把拖动的数据进行存储(称为编码),数据存储为QMimeData类型的对象(称为放置数据),当执行放置操作时需要把存储的数据读取出来(称为解码),然后进行处理。
自定义拖放操作的步骤:
(1)启用视图拖放支持
ui->treeView->setDragEnabled(true); //允许拖放,默认未启用
ui->treeView->setAcceptDrops(true); //接受放置数据
ui->treeView->setDragDropMode(QAbstractItemView::InternalMove); //拖放模式为移动
ui->treeView->setDropIndicatorShown(true); //显示拖放位置
ui->treeView->setDragDropOverwriteMode(true); //放下时覆盖已有项
(2)启用数据项的拖放支持
重新实现QAbstractItemModel::flags()函数以提供合适的标志来指示哪些项目可以被拖动,哪些项目将接受放置(Drop)。
(3)编码数据
重新实现QAbstractItemModel::mimeData()函数,把编码后的数据保存在该函数返回的QMimeData对象中。
(4)处理放置数据
重新实现QAbstractItemModel::dropMimeData()函数来处理放置数据,此时需要对放置数据进行解码(即读取出QMimeData对象存储的数据的内容),并将其插入模型的底层数据结构中(或进行其他处理),若该函数修改了数据项或模型的尺寸,则必须注意确保发出所有相关的信号。因为该函数需要插入或删除等操作,所以简单的调用QAbstractItemModel子类中的已经实现了的setData(),insertRows()和insertColumns()等函数会更方便。另外,还可以使用dropMimeData()函数的默认实现来处理放置数据,dropMimeData()函数的默认实现不会覆盖模型中的任何数据,它会将放置数据作为项目的同胞插入,或者作为该项目的子项插入。若要使用该函数的默认实现,就需要重新实现以下函数:insertRows()、insertColumns()、setData()、setItemData()。
示例如下:
//声明
virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override;
Qt::DropActions supportedDropActions() const override;
virtual QMimeData *mimeData(const QModelIndexList &indexes) const override;
bool moveRows(QModelIndex sourceParent, int first, int last, QModelIndex destParent, int pos);
//实现
bool TreeModel::dropMimeData(const QMimeData * data, Qt::DropAction action, int row, int column, const QModelIndex & parent)
{
QByteArray array = data->data(QString("hehe"));
QDataStream stream(&array, QIODevice::ReadOnly);
qint64 p;
stream >> p;
QModelIndex* index = (QModelIndex*)p;
/*
此处存在一个坑,百度查资料查了很久,都解释说parent是放下时的节点的父节点索引,但我测试发现这个parent就是当前放下时的节点索引,所以在这里就当目标节点索引使用了
*/
return moveRows(index->parent(), index->row(), index->row(), parent.parent(), parent.row());
}
Qt::DropActions TreeModel::supportedDropActions() const
{
return Qt::MoveAction;
}
QMimeData * TreeModel::mimeData(const QModelIndexList & indexes) const
{
QMimeData* mimeData = QAbstractItemModel::mimeData(indexes);
//只取第一个
for (int i = 0; i < indexes.count(); i++)
{
QModelIndex index = indexes[i];
QModelIndex* p = new QModelIndex(index);
TreeItem* item = static_cast<TreeItem*>(index.internalPointer());
qDebug() << item->data(Qt::DisplayRole).toString();
QByteArray array;
QDataStream stream(&array, QIODevice::WriteOnly);
stream << (qint64)p;
mimeData->setData(QString("hehe"), array);
return mimeData;
}
return mimeData;
}
bool TreeModel::moveRows(QModelIndex sourceParent, int first, int last, QModelIndex destParent, int pos)
{
bool ret = false;
if (!sourceParent.isValid() || !destParent.isValid())
return ret;
NetworkItem *srcItem = itemFromIndex(sourceParent);
NetworkItem *destItem = itemFromIndex(destParent);
if (beginMoveRows(sourceParent, first, last, destParent, pos))
{
if (destItem == srcItem)
{
//同级移动,即父节点相同
ret = destItem->moveChildren(first, last, pos);
}
else
{
ret = destItem->moveChildren(srcItem, first, last, pos);
}
endMoveRows();
}
return ret;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)