我有几个 JList 都可以作为 DnD COPY 操作的来源和目的地。它们工作得很好,但一方面 - 元素被添加到列表的底部,而不是我想要的放置目标行。
由于Oracle BasicDnD 示例包含此功能(事实上,它是我能够通过 Google 找到的唯一应用程序),我一直在查看它的源代码,看看我是否能够适应它。我试图设置 TransferHandler 对象,这是我想我缺少的,但没有出现新的行为。那么,我可能会错过/做错什么(其他)?
EDIT1:下面显示了我用于这些列表的类。
private class InteractiveJList extends JList implements DragGestureListener,
DragSourceListener, DropTargetListener {
private final DropTarget dropTarget;
private final DragSource dragSource;
private final boolean removeElementsOnFail;
private int[] selectedOnes;
@SuppressWarnings("unchecked")
private InteractiveJList(final ListModel model,
final boolean _removElementsOnFail) {
super(model);
this.dragSource = new DragSource();
this.dragSource
.createDefaultDragGestureRecognizer(this, DnDConstants.ACTION_COPY,
this);
this.dropTarget = new DropTarget(this, this);
this.removeElementsOnFail = _removElementsOnFail;
}
@Override
public void dragEnter(final DropTargetDragEvent arg0) {
}
@Override
public void dragExit(final DropTargetEvent arg0) {
}
@Override
public void dragOver(final DropTargetDragEvent arg0) {
}
@Override
public void drop(final DropTargetDropEvent event) {
if (!this.removeElementsOnFail) {
event.rejectDrop();
return;
}
final Transferable transferable = event.getTransferable();
if (transferable.isDataFlavorSupported(DataFlavor.stringFlavor)) {
String all;
try {
all = (String) transferable.getTransferData(DataFlavor.stringFlavor);
} catch (final UnsupportedFlavorException | IOException ex) {
event.rejectDrop();
return;
}
event.acceptDrop(DnDConstants.ACTION_COPY);
final StringTokenizer tokenizer = new StringTokenizer(all, "|");
while (tokenizer.hasMoreTokens()) {
((StringListModel) this.getModel()).addElement(tokenizer.nextToken());
}
event.getDropTargetContext().dropComplete(Boolean.TRUE);
} else {
event.rejectDrop();
}
}
@Override
public void dropActionChanged(final DropTargetDragEvent event) {
}
@Override
public void dragEnter(final DragSourceDragEvent arg0) {
}
@Override
public void dragExit(final DragSourceEvent arg0) {
}
@Override
public void dragOver(final DragSourceDragEvent arg0) {
}
@Override
public void dropActionChanged(final DragSourceDragEvent dragSourceEvent) {
}
@Override
public void dragGestureRecognized(final DragGestureEvent dragGestureEvent) {
final Object listSelectedValue = this.getSelectedValue();
this.selectedOnes = this.getSelectedIndices();
final StringBuilder bridge = new StringBuilder();
for (final int x : this.selectedOnes) {
bridge.append(this.getModel().getElementAt(x)).append("|");
}
if (listSelectedValue != null) {
final StringSelection stringTransferable =
new StringSelection(bridge.toString()
.substring(0, bridge.length() - 1));
this.dragSource.startDrag(dragGestureEvent, DragSource.DefaultCopyDrop,
stringTransferable, this);
}
}
@Override
public void dragDropEnd(final DragSourceDropEvent dragSourceDropEvent) {
if (!dragSourceDropEvent.getDropSuccess()) {
if (this.removeElementsOnFail) {
for (final int x : this.selectedOnes) {
((StringListModel) this.getModel()).removeElement(x);
}
}
}
}
}
使用构造函数中的布尔标志是因为,对于其中一个列表,如果丢弃操作被拒绝,则必须删除该元素,而不是另一个。这样我就可以处理了。StringListModel
是AbstractListModel处理字符串列表的扩展。它能够在底部和请求的位置添加元素,清除列表并删除某些元素。它做自己的事情,触发相应的事件,仅此而已。
EDIT2:下面显示了我对 MadProgrammer 建议的实施:
private static class UserTransferHandler extends TransferHandler {
private final JList list;
private UserTransferHandler(final JList list) {
this.list = list;
}
@Override
public boolean canImport(final TransferSupport support) {
System.out.println("canImport");
boolean canImport = false;
if (support.isDataFlavorSupported(UserTransferable.USER_DATA_FLAVOR)) {
final JList.DropLocation dl =
(JList.DropLocation) support.getDropLocation();
if (dl.getIndex() != -1) {
canImport = true;
}
}
return canImport;
}
@Override
protected void exportDone(final JComponent source, final Transferable data,
final int action) {
System.out.println("exportDone");
}
@Override
public boolean importData(final TransferSupport support) {
System.out.println("importData");
boolean accepted = false;
if (support.isDrop()) {
if (support.isDataFlavorSupported(UserTransferable.USER_DATA_FLAVOR)) {
final JList.DropLocation dl =
(JList.DropLocation) support.getDropLocation();
final StringListModel model = (StringListModel) this.list.getModel();
final int index = dl.getIndex();
final boolean insert = dl.isInsert();
final Transferable t = support.getTransferable();
try {
final String dropped = (String) t
.getTransferData(UserTransferable.USER_DATA_FLAVOR);
if (insert) {
if (index >= model.getSize()) {
model.addElement(dropped);
} else {
model.addElementAt(dropped, index);
}
} else {
model.addElement(dropped);
}
accepted = true;
} catch (final Exception e) {
e.printStackTrace();
}
}
}
return accepted;
}
@Override
public int getSourceActions(final JComponent c) {
System.out.println("getSourceActions");
return TransferHandler.COPY_OR_MOVE;
}
@Override
protected Transferable createTransferable(final JComponent c) {
System.out.println("createTransferable");
final String value = this.list.getSelectedValue().toString();
return new UserTransferable(value);
}
}
private static class UserTransferable implements Transferable {
private static final DataFlavor USER_DATA_FLAVOR =
new DataFlavor(String.class, "String");
private final String value;
private UserTransferable(final String value) {
System.out.println("UserTransferable");
this.value = value;
}
@Override
public DataFlavor[] getTransferDataFlavors() {
System.out.println("getTransferDataFlavors");
return new DataFlavor[] { UserTransferable.USER_DATA_FLAVOR };
}
@Override
public boolean isDataFlavorSupported(final DataFlavor flavor) {
System.out.println("isDataFlavorSupported");
return UserTransferable.USER_DATA_FLAVOR.equals(flavor);
}
@Override
public Object getTransferData(final DataFlavor flavor) throws
UnsupportedFlavorException, IOException {
System.out.println("getTransferData");
if (!UserTransferable.USER_DATA_FLAVOR.equals(flavor)) {
throw new UnsupportedFlavorException(flavor);
}
return this.value;
}
}
当调用方法时,打印语句可以获取反馈(现在,永远不会)。