我正在尝试将拖放功能与我们的产品结合起来。我创建了一个新的自定义视图,它具有树结构,并且有兴趣将内容从该树中删除到应用程序本身中已经存在的树结构中。
我使用了与产品预期相同的自定义传输类型。但是,在调试时我发现DragSourceEvent
' 的数据或数据类型都没有设置。两者都是null
价值观。此外,我dragSetData
的也没有被调用。
请求您给我一些建议......
我正在尝试将拖放功能与我们的产品结合起来。我创建了一个新的自定义视图,它具有树结构,并且有兴趣将内容从该树中删除到应用程序本身中已经存在的树结构中。
我使用了与产品预期相同的自定义传输类型。但是,在调试时我发现DragSourceEvent
' 的数据或数据类型都没有设置。两者都是null
价值观。此外,我dragSetData
的也没有被调用。
请求您给我一些建议......
事件的数据只有在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
解决方案
如果我们希望用户在不使用元键的情况下拖动条目,我们应该始终允许在拖放端进行系统默认的拖动操作。在 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));
解释
三组操作应该相交:
只有这样放置目标才会验证接收到的放置,并且会请求拖动源获取数据。
调查
元键的处理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
处理方式已损坏,不应依赖。如果第一个条件有效地防止了它的使用。