开始想使用QGraphicsView结合QGraphicsScene和QGraphicsItem,做个绘制各种图形的编辑器,想使用拖拽实现快捷方式,没想到还有点波折。
已在QGraphicsVews中设置了setAcceptDrops(true);
在运行时发现:当把拖拽的图标放到QGraphicsVews上时,显示的还是不可拖拽的形状,但dragEnterEvent可以触发。但后面的dropEvent就不能触发了。
上网一查,视图接收到拖拽事件后会转交给关联的场景处理,但是在场景中重写dropevent还是没有扑捉到事件。
今天实际跟踪了一下:
1、拖拽首先进入QGraphicsView触发其dragEnterEvent事件:
void QGraphicsView::dragEnterEvent(QDragEnterEvent *event) { #ifndef QT_NO_DRAGANDDROP Q_D(QGraphicsView); if (!d->scene || !d->sceneInteractionAllowed) return; // Disable replaying of mouse move events. d->useLastMouseEvent = false; // Generate a scene event. QGraphicsSceneDragDropEvent sceneEvent(QEvent::GraphicsSceneDragEnter); d->populateSceneDragDropEvent(&sceneEvent, event); // Store it for later use. d->storeDragDropEvent(&sceneEvent); // Send it to the scene. QApplication::sendEvent(d->scene, &sceneEvent); // Accept the originating event if the scene accepted the scene event. if (sceneEvent.isAccepted()) { event->setAccepted(true); event->setDropAction(sceneEvent.dropAction()); } #else Q_UNUSED(event) #endif }
2、场景的dragEnterEvent
void QGraphicsScene::dragEnterEvent(QGraphicsSceneDragDropEvent *event) { Q_D(QGraphicsScene); d->dragDropItem = 0; d->lastDropAction = Qt::IgnoreAction; event->accept(); }场景的dragenterEvent其实很简单就是接收拖拽事件
3、场景的dragMoveEvent事件,重点就在于此
void QGraphicsScene::dragMoveEvent(QGraphicsSceneDragDropEvent *event) { Q_D(QGraphicsScene); event->ignore(); if (!d->mouseGrabberItems.isEmpty()) { // Mouse grabbers that start drag events lose the mouse grab. d->clearMouseGrabber(); d->mouseGrabberButtonDownPos.clear(); d->mouseGrabberButtonDownScenePos.clear(); d->mouseGrabberButtonDownScreenPos.clear(); } bool eventDelivered = false; // Find the topmost enabled items under the cursor. They are all // candidates for accepting drag & drop events. foreach (QGraphicsItem *item, d->itemsAtPosition(event->screenPos(), event->scenePos(), event->widget())) { if (!item->isEnabled() || !item->acceptDrops()) continue; if (item != d->dragDropItem) { // Enter the new drag drop item. If it accepts the event, we send // the leave to the parent item. QGraphicsSceneDragDropEvent dragEnter(QEvent::GraphicsSceneDragEnter); d->cloneDragDropEvent(&dragEnter, event); dragEnter.setDropAction(event->proposedAction()); d->sendDragDropEvent(item, &dragEnter); event->setAccepted(dragEnter.isAccepted()); event->setDropAction(dragEnter.dropAction()); if (!event->isAccepted()) { // Propagate to the item under continue; } d->lastDropAction = event->dropAction(); if (d->dragDropItem) { // Leave the last drag drop item. A perfect implementation // would set the position of this event to the point where // this event and the last event intersect with the item's // shape, but that's not easy to do. :-) QGraphicsSceneDragDropEvent dragLeave(QEvent::GraphicsSceneDragLeave); d->cloneDragDropEvent(&dragLeave, event); d->sendDragDropEvent(d->dragDropItem, &dragLeave); } // We've got a new drag & drop item d->dragDropItem = item; } // Send the move event. event->setDropAction(d->lastDropAction); event->accept(); d->sendDragDropEvent(item, event); if (event->isAccepted()) d->lastDropAction = event->dropAction(); eventDelivered = true; break; } if (!eventDelivered) { if (d->dragDropItem) { // Leave the last drag drop item QGraphicsSceneDragDropEvent dragLeave(QEvent::GraphicsSceneDragLeave); d->cloneDragDropEvent(&dragLeave, event); d->sendDragDropEvent(d->dragDropItem, &dragLeave); d->dragDropItem = 0; } // Propagate event->setDropAction(Qt::IgnoreAction); } }
很显然,在拖拽移动过程中忽略了该事件,主要响应的是场景内可能存在的item拖拽事件
看到这,问题就有答案了,subclass场景类,重写dragMoveEvent
void QGraphicsScene::dragMoveEvent(QGraphicsSceneDragDropEvent *event) { event->accept(); }