详解QT下拖动操作Drag-Drop的实现

QT下实现Drag-Drop是极其容易的,下面给大家介绍一下。

所谓拖动,自动有一个源窗口,一个目标窗口,不过有时候源窗口与目的窗口是同一个窗口。

源窗口

在鼠标Press的时候,记录起始点为dragPosition(此为成员变量);在Move的时候,检测与起始点的距离,当拖动一定距离的时候,认为开启了一个拖动操作。按下面例子,鼠标会为成拖动的样式,并有一个图片显示被拖动的物体的轮廓。

void HostTree::mouseMoveEvent ( QMouseEvent * event )
{
	if (!(event->buttons() & Qt::LeftButton))
		return;

	if ((event->pos() - dragPosition).manhattanLength()	< QApplication::startDragDistance())
		return;
	
	QDrag *drag = new QDrag(this);
	QMimeData *mimeData = new QMimeData;

	// 把ip地址传出
	mimeData->setData("custom/host_free", ...设置一个ByteArray... );
	drag->setMimeData(mimeData);

	// 设置图片
	QPixmap drag_img(120, 18);
	QPainter painter(&drag_img);
	painter.drawText(QRectF(0,0, 120,18), ... 拖动时图片信息.. , QTextOption(Qt::AlignVCenter));
	drag->setPixmap(drag_img);

	Qt::DropAction resultAction = drag->exec(Qt::MoveAction);
	if(resultAction == Qt::MoveAction)
	{
		// 确认移动操作
		// 该操作已经被目标操作接受,且操作类型为MOVE,一般来说应该把被拖动的物体从源窗口删除
	}

	//QTreeWidget::mouseMoveEvent(event);
}

void HostTree::mousePressEvent ( QMouseEvent * event ) 
{
	if (event->button() == Qt::LeftButton)
	{
		dragItem = itemAt(event->pos());
		dragPosition = event->pos();
	}

	QTreeWidget::mousePressEvent(event);	
}


目标窗口

首先这个Widget要设置

setAcceptDrops(true);


然后要重写drop的4大操作, 即enter leave move drop。

首先说enter,表示拖动操作进入本窗口,是接受还是拒绝,是一个需要思考的问题。其标准是检测该其mine data的格式, 即hasFormat()来判断。如果该event被ignore,则鼠标在窗口中会显示一个forbidden状态的圆圈,表示禁止拖进来。

void  TopoTree::dragEnterEvent ( QDragEnterEvent * event ) 
{
	//qDebug("dragEnterEvent: enter drag mode ............");

	if(event->mimeData()->hasFormat("custom/host_free"))
	{
		m_dragMode = 1;
		event->acceptProposedAction();
	}
	else
	{
		event->ignore();
		QTreeWidget::dragEnterEvent(event);
	}
}

第2个是leave,表示离开本窗口,即用户拖动东西进来,但是没有drop放下来又走了。那么把m_dragMode=0回到原状态。这个m_dragMode你爱加不加,不过一般会用到此状态。

void  TopoTree::dragLeaveEvent ( QDragLeaveEvent * event ) 
{
 	//qDebug("exit topotree, exit drag mode ............");
	m_dragMode = 0;

	QTreeWidget::dragLeaveEvent(event);
}

第3个是move,用户拖动东西在目标窗口内游荡,在拖到某此点位时,应提示允许其drop放下。比如目标窗口里有若干个坑,那么当鼠标over到坑上时,就应该提示这里可以drop并改变鼠标形状。

void  TopoTree::dragMoveEvent ( QDragMoveEvent * event ) 
{
	if(event->mimeData()->hasFormat("custom/host_free"))
	{
		QTreeWidgetItem* itemOver = itemAt(event->pos());
		if(itemOver == NULL)
		{
		}
		else
		{
			// accept
			event->acceptProposedAction();
			//QTreeWidget::dragMoveEvent(event);
			return;
		}
	}
	
	event->ignore();
	QTreeWidget::dragMoveEvent(event);
}


最后一个是drop,这个是重头戏,即某个点位用户放开了鼠标完成drop操作。一般来说,应该解析出该drag所携带的 data ,然后做一个插入操作。调用acceptProposedAction()来通知源窗口,说此操作已经被接受,源窗口应于此时做一个删除/复制操作。

void  TopoTree::dropEvent ( QDropEvent * event ) 
{
	if(event->mimeData()->hasFormat("custom/host_free"))
	{
		QTreeWidgetItem* itemOver = itemAt(event->pos());
		if(itemOver != NULL)
		{
			// 接收此MoveAction,插入节点
			
			// 提取drag中携带的信息
			QByteArray data = event->mimeData()->data("custom/host_free");
			// 新建节点
			this->setCurrentItem(item); // 设置为当前选中
			this->m_dragMode = 0; // 结束drag mode
			event->acceptProposedAction();
			//QTreeWidget::dropEvent(event);
			return;
		}
	}

	event->ignore();
	QTreeWidget::dropEvent(event);
}


怎么样,讲得够清楚了吗,呵呵。

 

----------------------------------------------------------------------------------------------------------------------------------

《C/C++学习指南》 - 我的讲C/C++的教程,一看就懂的教程,所有必须要懂的知识点,来吧! 适用于初学者及三年工作经验以内的同学,配套答疑平台,“让编程变得简单!”。



你可能感兴趣的:(详解QT下拖动操作Drag-Drop的实现)