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);
- }
怎么样,讲得够清楚了吗,呵呵。