开始想使用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,做最后拖拽处理就是了。