開始想使用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();}
最後重寫dropEvent,做最後拖拽處理就是了。