将字符串添加到JList的确切位置,而不是底部

我有几个JList都可以成为DnD COPY动作的源和目的地。 它们工作正常,但有一点 – 元素添加在列表的底部,而不是像我想的那样添加到放置目标行。

由于Oracle BasicDnD示例包含此function(事实上,它是我能通过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的扩展,用于处理字符串列表。 它能够在底部和请求的位置添加元素,清除列表,并删除某些元素。 它做了它的东西,发射相应的事件,没有进一步。

编辑2:下面显示了我对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; } } 

打印语句用于在调用方法时获得反馈(现在,从不)。

这是一个使用(较新的) Transferable API的完整工作示例。 这是基于您链接的示例。

请注意,我并没有因使用String而烦恼,因为这只会让人感到困惑,相反,我正在转移对象。

另请注意,我正在使用“移动”API,因此名称将从一个列表移动到另一个列表…

在此处输入图像描述

 import java.awt.*; import java.awt.event.*; import java.awt.datatransfer.*; import java.io.IOException; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.*; public class ComponentAPIDnD { public static void main(String[] args) { new ComponentAPIDnD(); } public ComponentAPIDnD() { EventQueue.invokeLater(new Runnable() { @Override public void run() { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { } JFrame frame = new JFrame("Testing"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setLayout(new BorderLayout()); frame.add(new TestPane()); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); } }); } public class TestPane extends JPanel { private JList left; private JList right; public TestPane() { setLayout(new GridLayout(0, 2)); DefaultListModel model = new DefaultListModel<>(); model.addElement(new User("Rai")); model.addElement(new User("Mark")); model.addElement(new User("Han")); model.addElement(new User("Luke")); model.addElement(new User("Ben")); model.addElement(new User("Yoda")); left = new JList(model); left.setCellRenderer(new UserListCellRenderer()); right = new JList(new DefaultListModel()); right.setCellRenderer(new UserListCellRenderer()); left.setName("Left"); right.setName("Right"); add(new JScrollPane(left)); add(new JScrollPane(right)); left.setTransferHandler(new UserTransferHandler(left)); right.setTransferHandler(new UserTransferHandler(right)); left.setDropMode(DropMode.ON_OR_INSERT); right.setDropMode(DropMode.ON_OR_INSERT); left.setDragEnabled(true); right.setDragEnabled(true); } @Override public Dimension getPreferredSize() { return new Dimension(400, 400); } } public static class UserTransferHandler extends TransferHandler { private JList list; public UserTransferHandler(JList list) { this.list = list; } @Override public boolean canImport(TransferSupport support) { boolean canImport = false; if (support.isDataFlavorSupported(UserTransferable.USER_DATA_FLAVOR)) { JList.DropLocation dl = (JList.DropLocation) support.getDropLocation(); if (dl.getIndex() != -1) { canImport = true; } } return canImport; } @Override protected void exportDone(JComponent source, Transferable data, int action) { try { User user = (User) data.getTransferData(UserTransferable.USER_DATA_FLAVOR); ((DefaultListModel)list.getModel()).removeElement(user); } catch (UnsupportedFlavorException | IOException ex) { ex.printStackTrace(); } } @Override public boolean importData(TransferSupport support) { boolean accepted = false; if (support.isDrop()) { if (support.isDataFlavorSupported(UserTransferable.USER_DATA_FLAVOR)) { JList.DropLocation dl = (JList.DropLocation)support.getDropLocation(); DefaultListModel model = (DefaultListModel) list.getModel(); int index = dl.getIndex(); boolean insert = dl.isInsert(); Transferable t = support.getTransferable(); try { User dropped = (User) t.getTransferData(UserTransferable.USER_DATA_FLAVOR); System.out.println("Drop " + dropped + " on " + list.getName()); if (insert) { if (index >= model.getSize()) { model.addElement(dropped); } else { model.add(index, dropped); } } else { model.addElement(dropped); } accepted = true; } catch (Exception e) { e.printStackTrace(); } } } return accepted; } @Override public int getSourceActions(JComponent c) { return COPY_OR_MOVE; } @Override protected Transferable createTransferable(JComponent c) { User user = (User) list.getSelectedValue(); return new UserTransferable(user); } } public static class UserTransferable implements Transferable { public static final DataFlavor USER_DATA_FLAVOR = new DataFlavor(User.class, "User"); private User user; public UserTransferable(User user) { this.user = user; } @Override public DataFlavor[] getTransferDataFlavors() { return new DataFlavor[] {USER_DATA_FLAVOR}; } @Override public boolean isDataFlavorSupported(DataFlavor flavor) { return USER_DATA_FLAVOR.equals(flavor); } @Override public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException { Object value = null; if (USER_DATA_FLAVOR.equals(flavor)) { value = user; } else { throw new UnsupportedFlavorException(flavor); } return user; } } public class User { private String name; public User(String name) { this.name = name; } public String getName() { return name; } } public class UserListCellRenderer extends DefaultListCellRenderer { @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); if (value instanceof User) { setText(((User) value).getName()); } return this; } } }