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++的教程,一看就懂的教程,所有必须要懂的知识点,来吧! 适用于初学者及三年工作经验以内的同学,配套答疑平台,“让编程变得简单!”。