【问题标题】:Not able to implement drag and drop; dragSetData not getting called无法实现拖放;没有调用dragSetData
【发布时间】:2013-04-16 07:54:04
【问题描述】:

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

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

请你给我一些建议....

【问题讨论】:

    标签: java drag-and-drop tree swt


    【解决方案1】:

    事件的数据只有在drop获取数据后才设置。这应该会自动发生,但一开始对我也不起作用。

    经过一些研究,我想出了一个解决方法,尽管我不确定这是否是框架的意图。我在我的解决方案中扩展了 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 文档 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
    

    【讨论】:

      【解决方案2】:

      解决方案

      如果我们希望用户不使用元键拖动条目,我们应该始终允许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() 设置)
      • 用户选择的操作(取决于放置时按下了哪些元键)

      只有这样放置目标才会验证接收到的放置,并且会请求拖动源获取数据。

      调查

      元键的处理在org.eclipse.swt.dnd.DropTarget.setEventData()这一行完成

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

      来自 droptarget 的样式与来自系统 drop 操作的值相交是基于 dragsource 但剥夺了DND.DRAG_DEFAULT。如果这两者不相交,则中止操作。

      再往下,该集合与根据按下的元键计算的集合进行比较。操作可能会再次中止。

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

      可以通过将DND.DROP_DEFAULT 传递给addDropSupport() 来控制此行为,但更糟糕的是,用户选择的操作将与DND.DROP_MOVE 进行比较,如果不用作@ 的参数,则会更早过滤掉987654330@.

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-06-29
        • 1970-01-01
        • 2022-12-25
        • 2014-12-01
        • 2019-11-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多