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

时间:2013-03-20 18:25:13

标签: java swing drag-and-drop jlist transfer

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

由于Oracle BasicDnD example包含此功能(实际上,它是我通过Google可以找到的唯一应用程序),我一直在查看其source到看看我是否能够适应它。我试图设置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);
        }
    }
    }
}

}

使用构造函数中的布尔标志,因为对于其中一个列表,如果放弃操作被拒绝,则必须删除该元素,但不能删除另一个元素。这样我就能解决这个问题。 StringListModelAbstractListModel的扩展名,用于处理字符串列表。它能够在底部和请求的位置添加元素,清除列表,并删除某些元素。它做了它的东西,发射相应的事件,没有进一步。

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;
}

}

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

1 个答案:

答案 0 :(得分:3)

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

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

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

enter image description here

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<User> 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<User>());
            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<User>)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<User> model = (DefaultListModel<User>) 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;
        }
    }
}