我有几个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);
}
}
}
}
}
使用构造函数中的布尔标志,因为对于其中一个列表,如果放弃操作被拒绝,则必须删除该元素,但不能删除另一个元素。这样我就能解决这个问题。 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;
}
}
打印语句可以在调用方法时获得反馈(现在,从不)。
答案 0 :(得分:3)
这是一个使用(较新的)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<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;
}
}
}