QGraphicsView 中实现拖拽

来源:互联网 发布:国产js 12.7mm狙击步枪 编辑:程序博客网 时间:2024/06/10 05:38

开始想使用QGraphicsView结合QGraphicsScene和QGraphicsItem,做个绘制各种图形的编辑器,想使用拖拽实现快捷方式,没想到还有点波折。

已在QGraphicsVews中设置了setAcceptDrops(true);

在运行时发现:当把拖拽的图标放到QGraphicsVews上时,显示的还是不可拖拽的形状,但dragEnterEvent可以触发。但后面的dropEvent就不能触发了。

上网一查,视图接收到拖拽事件后会转交给关联的场景处理,但是在场景中重写dropevent还是没有扑捉到事件。

今天实际跟踪了一下:


1、拖拽首先进入QGraphicsView触发其dragEnterEvent事件:

[cpp] view plaincopyprint?
  1. void QGraphicsView::dragEnterEvent(QDragEnterEvent *event)  
  2. {  
  3. #ifndef QT_NO_DRAGANDDROP  
  4.     Q_D(QGraphicsView);  
  5.     if (!d->scene || !d->sceneInteractionAllowed)  
  6.         return;  
  7.   
  8.     // Disable replaying of mouse move events.  
  9.     d->useLastMouseEvent = false;  
  10.   
  11.     // Generate a scene event.  
  12.     QGraphicsSceneDragDropEvent sceneEvent(QEvent::GraphicsSceneDragEnter);  
  13.     d->populateSceneDragDropEvent(&sceneEvent, event);  
  14.   
  15.     // Store it for later use.  
  16.     d->storeDragDropEvent(&sceneEvent);  
  17.   
  18.     // Send it to the scene.   
  19.     QApplication::sendEvent(d->scene, &sceneEvent);  
  20.   
  21.     // Accept the originating event if the scene accepted the scene event.  
  22.     if (sceneEvent.isAccepted()) {  
  23.         event->setAccepted(true);  
  24.         event->setDropAction(sceneEvent.dropAction());  
  25.     }  
  26. #else   
  27.     Q_UNUSED(event)  
  28. #endif   
  29. }  

上述函数主要是查看有没有场景,然后将事件转交给场景处理,当然是在条件允许的情况下转交给场景处理。

2、场景的dragEnterEvent

[cpp] view plaincopyprint?
  1. void QGraphicsScene::dragEnterEvent(QGraphicsSceneDragDropEvent *event)  
  2. {  
  3.     Q_D(QGraphicsScene);  
  4.     d->dragDropItem = 0;  
  5.     d->lastDropAction = Qt::IgnoreAction;  
  6.     event->accept();  
  7. }  
场景的dragenterEvent其实很简单就是接收拖拽事件

3、场景的dragMoveEvent事件,重点就在于此

[cpp] view plaincopyprint?
  1. <SPAN style="COLOR: #333333">void QGraphicsScene::dragMoveEvent(QGraphicsSceneDragDropEvent *event)  
  2. {  
  3.     Q_D(QGraphicsScene);  
  4.     </SPAN><SPAN style="COLOR: #ff0000">event->ignore();</SPAN><SPAN style="COLOR: #333333">  
  5.   
  6.     if (!d->mouseGrabberItems.isEmpty()) {  
  7.         // Mouse grabbers that start drag events lose the mouse grab.  
  8.         d->clearMouseGrabber();  
  9.         d->mouseGrabberButtonDownPos.clear();  
  10.         d->mouseGrabberButtonDownScenePos.clear();  
  11.         d->mouseGrabberButtonDownScreenPos.clear();  
  12.     }  
  13.   
  14.     bool eventDelivered = false;  
  15.   
  16.     // Find the topmost enabled items under the cursor. They are all  
  17.     // candidates for accepting drag & drop events.  
  18.     foreach (QGraphicsItem *item, d->itemsAtPosition(event->screenPos(),  
  19.                                                      event->scenePos(),  
  20.                                                      event->widget())) {  
  21.         if (!item->isEnabled() || !item->acceptDrops())  
  22.             continue;  
  23.   
  24.         if (item != d->dragDropItem) {  
  25.             // Enter the new drag drop item. If it accepts the event, we send  
  26.             // the leave to the parent item.  
  27.             QGraphicsSceneDragDropEvent dragEnter(QEvent::GraphicsSceneDragEnter);  
  28.             d->cloneDragDropEvent(&dragEnter, event);  
  29.             dragEnter.setDropAction(event->proposedAction());  
  30.             d->sendDragDropEvent(item, &dragEnter);  
  31.             event->setAccepted(dragEnter.isAccepted());  
  32.             event->setDropAction(dragEnter.dropAction());  
  33.             if (!event->isAccepted()) {  
  34.                 // Propagate to the item under  
  35.                 continue;  
  36.             }  
  37.   
  38.             d->lastDropAction = event->dropAction();  
  39.   
  40.             if (d->dragDropItem) {  
  41.                 // Leave the last drag drop item. A perfect implementation  
  42.                 // would set the position of this event to the point where  
  43.                 // this event and the last event intersect with the item's  
  44.                 // shape, but that's not easy to do. :-)  
  45.                 QGraphicsSceneDragDropEvent dragLeave(QEvent::GraphicsSceneDragLeave);  
  46.                 d->cloneDragDropEvent(&dragLeave, event);  
  47.                 d->sendDragDropEvent(d->dragDropItem, &dragLeave);  
  48.             }  
  49.   
  50.             // We've got a new drag & drop item  
  51.             d->dragDropItem = item;  
  52.         }  
  53.   
  54.         // Send the move event.   
  55.         event->setDropAction(d->lastDropAction);  
  56.         event->accept();  
  57.         d->sendDragDropEvent(item, event);  
  58.         if (event->isAccepted())  
  59.             d->lastDropAction = event->dropAction();  
  60.         eventDelivered = true;  
  61.         break;  
  62.     }  
  63.   
  64.     if (!eventDelivered) {  
  65.         if (d->dragDropItem) {  
  66.             // Leave the last drag drop item  
  67.             QGraphicsSceneDragDropEvent dragLeave(QEvent::GraphicsSceneDragLeave);  
  68.             d->cloneDragDropEvent(&dragLeave, event);  
  69.             d->sendDragDropEvent(d->dragDropItem, &dragLeave);  
  70.             d->dragDropItem = 0;  
  71.         }  
  72.         // Propagate   
  73.         event->setDropAction(Qt::IgnoreAction);  
  74.     }  
  75. }  
  76. </SPAN>  

很显然,在拖拽移动过程中忽略了该事件,主要响应的是场景内可能存在的item拖拽事件



看到这,问题就有答案了,subclass场景类,重写dragMoveEvent

[cpp] view plaincopyprint?
  1. void QGraphicsScene::dragMoveEvent(QGraphicsSceneDragDropEvent *event)  
  2. {  
  3.     event->accept();  
  4. }  

最后重写dropEvent,做最后拖拽处理就是了。


[cpp] view plaincopyprint?
  1. <PRE class=cpp style="MARGIN: 4px 0px; BACKGROUND-COLOR: rgb(240,240,240)" name="code"></PRE>  
  2. <PRE></PRE>  
原创粉丝点击