-1

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 ステートメントは、メソッドが呼び出されたときにフィードバックを取得するためにあります (現時点では決してありません)。

4

1 に答える 1

3

これは、(新しい) TransferableAPI を使用する完全に機能する例です。これは、リンクした例に基づいています。

Stringこれは人々を混乱させるだけなので、私はわざわざ sを使用していないことに注意してください。代わりに、オブジェクトを転送しています。

また、私は「移動」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<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;
        }
    }
}
于 2013-03-20T23:05:38.937 に答える