无法实现拖放; dragSetData没有被调用

时间:2013-04-16 07:54:05

标签: java drag-and-drop tree swt

我正在尝试在我们的产品中加入拖放功能。我创建了一个新的自定义视图,它具有树结构,并且有兴趣将该树中的内容放到应用程序本身的现有树结构中。

我使用了产品所期望的相同自定义传输类型。但是,在调试时我发现DragSourceEvent的数据或数据类型都没有设置。 两者都是null值。此外,我的dragSetData也没有被调用。

请你提供一些建议......

2 个答案:

答案 0 :(得分:0)

事件的数据仅在丢弃获取数据后设置。这应该会自动发生,但最初也不适用于我。

经过一番研究后,我想出了一个解决方法,虽然我不确定这是否是框架的意图。我在我的解决方案中扩展了 org.eclipse.jface.viewers.ViewerDropAdapter ,但它也适用于扩展 org.eclipse.swt.dnd.DropTargetAdapter

public class MyViewerDropAdapter extends ViewerDropAdapter {
    // implement the abstract methods

    // the next two methods are the important part: 
    // override the non-abstract methods dragEnter and dragOperationChanged
    // if your user just moves the mouse without pressing a key, event.detail
    // equals DND.DROP_DEFAULT. In this case you have to change detail to
    // your default operation (in this case DROP_COPY)
    @Override
    public void dragEnter(DropTargetEvent event) {
       if (event.detail == DND.DROP_DEFAULT) {
         if ((event.operations & DND.DROP_COPY) != 0) {
          event.detail = DND.DROP_COPY;
         } else {
          event.detail = DND.DROP_NONE;
         }
        }
      super.dragEnter(event);
    }

    // the same for this method. It will be called, when the user
    // presses the CTRL or SHIFT button (on windows) while dragging.
    // We need it here to set the DROP_DEFAULT back to DROP_COPY.
    // Otherwise your default will go back to DROP_NONE after the user
    // released the key.
    @Override
   public void dragOperationChanged(DropTargetEvent event) {
      if (event.detail == DND.DROP_DEFAULT) {
       if ((event.operations & DND.DROP_COPY) != 0) {
        event.detail = DND.DROP_COPY;
       } else {
        event.detail = DND.DROP_NONE;
       }
      }
   }
}

然后将删除支持添加到树查看器时,请确保除了其他操作之外还设置DND.DROP_DEFAULT操作(API doc afaik中未提及):

myTreeViewer.addDropSupport(DND.DROP_COPY | DND.DROP_DEFAULT,
            new Transfer[] { myByteTransfer.getInstance() },
            new MyViewerDropAdapter(myTreeViewer));

执行此操作后,调用了dragSetData,一切都按预期工作。

控制台输出显示某些事件的顺序:

Start Drag
dragEnter called
dragSetData called
drop called
performDrop called
Finshed Drag

答案 1 :(得分:0)

<强>解决方案

如果我们希望用户在不使用元键的情况下拖动条目,我们应该始终在拖放结束时允许 system-default 拖动操作。在Windows上,这恰好是DND.DRAG_MOVE操作(我相信其他平台也是如此)。

source.addDragSupport(DND.DROP_MOVE, new Transfer[] { DragSelectionListener.getTransfer() }, new DragSelectionListener(viewer));
target.addDropSupport(DND.DROP_MOVE, new Transfer[]{ DropListListener.getTransfer() }, new DropListListener(viewer));

<强>解释

三组操作应相交:

  • 拖动源允许的操作(使用StructuredViewer.addDragSupport()设置)
  • 拖动目标支持的操作(使用StructuredViewer.addDropSupport()设置)
  • 用户选择的操作(取决于丢弃时按下的元键)

然后,drop target将验证收到的丢弃,并且将请求拖动源数据。

<强>研究

元键的处理在org.eclipse.swt.dnd.DropTarget.setEventData()

中完成
operations[0] = osToOp(operations[0]) & style;
if (operations[0] == DND.DROP_NONE) return false;

将来自droptarget的样式与来自系统删除操作的值相交,它基于dragsource但被剥离DND.DRAG_DEFAULT。如果这两个不相交,则操作中止。

再将此设置与按下的元键计算出的设置进行比较。操作可以再次中止。

if ((operation & operations[0]) == 0) operation = DND.DROP_NONE;

可以控制此行为从DND.DROP_DEFAULT传递到addDropSupport(),但这更糟糕,因为用户选择的操作将与DND.DROP_MOVE进行比较,如果不是,则会先过滤掉用作addDropSupport()的参数。

我认为DND.DROP_DEFAULT处理已经破坏,不应该依赖。如果第一个条件有效地阻止了它的使用。