QTreeView节点拖放

拖放操作分为拖动(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;
}

  • 2
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
### 回答1: QTreeViewQt的一个控件,用于显示树形结构的数据。它提供了拖拽节点的功能,可以将节点拖拽到其他位置。 要实现节点拖拽,我们需要先将拖拽支持打开。在QTreeView中调用setDragEnabled(true)函数即可开启拖拽支持。 接下来,在需要拖拽节点上调用setDragEnabled(true)函数,表示该节点可以被拖拽。我们可以在构建树形结构数据时,为需要支持拖拽节点设置这个属性。 然后,我们需要实现三个事件处理函数:dragEnterEvent、dragMoveEvent和dropEvent。dragEnterEvent函数在拖拽进入TreeView控件时被调用,dragMoveEvent函数在拖拽过程中被调用,dropEvent函数在拖拽结束时被调用。 在dragEnterEvent和dragMoveEvent函数中,我们需要设置拖拽的操作类型和反馈。可以调用event->setDropAction(Qt::MoveAction)函数设置操作类型为移动操作。调用event->accept()函数表示接受拖拽操作。 在dropEvent函数中,我们需要实现节点的真实移动。可以通过调用model的removeRow和insertRow函数来移动节点的位置。 最后,我们可以在我们自定义的Model中重新实现mimeData函数和dropMimeData函数,来自定义节点的数据格式和处理。 通过以上步骤,我们就可以实现在QTreeView控件中拖拽节点的功能了。 ### 回答2: QTreeViewQt框架中的一个控件,用于显示树状结构的数据。它提供了一个可进行拖拽节点功能,允许用户在树中拖动节点到其他位置。 要实现QTreeView节点拖拽功能,需要进行以下步骤: 1. 设置QTreeView为可拖拽模式: QTreeView通过setDragEnabled(true)方法来启用节点拖拽功能。 2. 实现节点拖拽的数据源: 通过实现数据源类,在该类中重写mimeData()方法来指定拖拽时传输的数据。一般可以使用QMimeData类来创建自定义的数据类型,并将需要传输的数据保存在其中。 3. 设置数据源属性: 调用QTreeView的setDragDropMode()方法,并设置为QAbstractItemView::DragOnly模式,以指定控件为拖拽操作的数据源。 4. 处理拖拽操作的事件: 在QTreeView中,可以通过重写dragEnterEvent()、dragMoveEvent()和dropEvent()方法,来处理拖拽操作的事件。其中,dragEnterEvent()方法用于指定拖拽源和接收者的行为,dragMoveEvent()方法用于更新拖拽源和接收者之间的显示,dropEvent()方法则用于处理拖拽操作完成后的处理逻辑。 5. 处理拖拽节点位置的变化: 拖拽节点时,节点在树中的位置会发生变化。因此,在dropEvent()方法中,需要实现逻辑来更新节点在树中的位置。 通过以上步骤的实现,可以实现QTreeView拖拽节点功能。用户可以通过拖动节点,将其移动到其他位置,并且在操作完成后,可以根据需求进行后续的处理逻辑,例如更新数据模型或界面显示等。 ### 回答3: 在使用QTreeView实现节点拖拽的过程中,主要涉及到以下几个步骤。 首先,我们需要设置QTreeView拖拽模式,通过设置setDragEnabled(True)来启用节点拖拽功能。同时,还可以设置setDragDropMode(QAbstractItemView.DragDrop)来指定拖拽和放置的模式。 接下来,我们需要重写QTreeView的相关方法,以实现节点拖放操作。我们可以重写dragEnterEvent()方法,用于设置拖拽进入时所显示的状态以及接受拖拽的操作。我们也可以重写dragMoveEvent()方法,用于设置拖拽过程中的状态。 然后,我们还需要重写dropEvent()方法,用于处理节点的放置操作。在这个方法中,我们可以获取拖拽节点以及目标放置的位置,然后进行相应的处理。比如,我们可以通过QStandardItemModel的相关方法进行节点的移动操作,比如insertRow()方法可以在目标位置插入节点,removeRow()方法可以移除拖拽节点。 最后,我们需要设置节点的可拖拽和可放置的操作,通过设置基于节点角色和数据的标志位来实现。我们可以通过setDragDropOverwriteMode(False)来设置放置操作时是否重写源数据,还可以通过setDropIndicatorShown(True)来设置放置时是否显示指示器。 以上就是使用QTreeView实现节点拖拽的基本步骤。在实际应用中,我们可以根据具体的需求进行相应的扩展和优化,以实现更复杂的功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值