QGraphicsView 中实现拖拽

来源:互联网 发布:block图片轮播js代码 编辑:程序博客网 时间:2024/06/06 02:08


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