DnD COPY アクションのソースと宛先の両方にできる JList がいくつかあります。それらは正常に機能しますが、1 つには、要素がドロップ先の行ではなく、リストの一番下に追加されることです。
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);
}
}
}
}
}
リストの 1 つでドロップ アクションが拒否された場合、要素を削除する必要がありますが、別のリストでは削除しないため、コンストラクターのブール フラグが使用されます。このように私はそれを扱うことができます。String のリストを処理するためのAbstractListModelStringListModel
の拡張です。下部と要求された位置の両方に要素を追加したり、リストをクリアしたり、特定の要素を削除したりできます。それは自分の仕事をし、対応するイベントを発生させ、それ以上何もしません。
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;
}
}
print ステートメントは、メソッドが呼び出されたときにフィードバックを取得するためにあります (現時点では決してありません)。