使用拖放重新排序JList

我遇到了一个关于使用拖放重新排序JList中的元素的问题。 以下代码是对代码的修改,您可以将元素从一个JList拖动到另一个JList(仅以一种方式工作)。 我试图让它只用于一个JList,但是元素甚至不能被拖出列表。 所以我想这不可能这样做。 我有什么不对的想法?

我的想法是让它为带有缩略图的Jlist工作,但因为我甚至无法让它只使用字符串…我一直在研究几个D’n’D教程,但我仍然不能让它工作。 任何帮助表示赞赏。

import javax.swing.*; import javax.swing.border.*; import java.awt.*; import java.awt.datatransfer.*; import java.io.IOException; public class DragAndDrop extends JFrame { DefaultListModel transport = new DefaultListModel(); JList transportList = new JList(transport); public DragAndDrop() { setLayout(new FlowLayout()); transport.addElement("Bike"); transport.addElement("Car"); transport.addElement("Truck"); transport.addElement("Boat"); JScrollPane transportScroll = new JScrollPane(transportList); transportScroll.setBorder(new TitledBorder("Transportation")); add(transportScroll); transportList.setDragEnabled(true); transportList.setTransferHandler(new TransferHandler() { int index; @Override public int getSourceActions(JComponent comp) { return COPY_OR_MOVE; } @Override public Transferable createTransferable(JComponent comp) { index = transportList.getSelectedIndex(); return new StringSelection(transportList.getSelectedValue()); } @Override public void exportDone( JComponent comp, Transferable trans, int action ) { if (action==MOVE) { transport.remove(index); } } }); transportList.setDropMode(DropMode.ON); transportList.setTransferHandler(new TransferHandler() { @Override public boolean canImport(TransferHandler.TransferSupport support) { // data of type string? return support.isDataFlavorSupported(DataFlavor.stringFlavor); } @Override public boolean importData(TransferHandler.TransferSupport support) { try { // convert data to string String s = (String)support.getTransferable().getTransferData(DataFlavor.stringFlavor); JList.DropLocation dl = (JList.DropLocation)support.getDropLocation(); transport.add(dl.getIndex(),s); return true; } catch (UnsupportedFlavorException e) {} catch (IOException e) {} return false; } }); pack(); setDefaultCloseOperation(EXIT_ON_CLOSE); setVisible(true); } public static void main(String[] args) { new DragAndDrop(); } } 

PS。 对不起,如果这是一个重新发布。

编辑我认为我修复了它:不得不使用不同的transferHandlers – 只应该有一个包含第二个方法的所有方法。

在此处输入图像描述

 import java.awt.BorderLayout; import java.awt.Component; import java.awt.EventQueue; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.awt.dnd.DragSource; import java.io.IOException; import java.io.Serializable; import java.util.Arrays; import java.util.Objects; // import javax.activation.ActivationDataFlavor; // import javax.activation.DataHandler; import javax.swing.BorderFactory; import javax.swing.DefaultListModel; import javax.swing.DropMode; import javax.swing.Icon; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.ListCellRenderer; import javax.swing.ListSelectionModel; import javax.swing.TransferHandler; import javax.swing.UIManager; import javax.swing.WindowConstants; public class DragAndDropTest { public JComponent makeUI() { DefaultListModel m = new DefaultListModel<>(); for (String s : Arrays.asList("error", "information", "question", "warning")) { m.addElement(new Thumbnail(s)); } JList list = new JList<>(m); list.getSelectionModel().setSelectionMode( ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); list.setTransferHandler(new ListItemTransferHandler()); list.setDropMode(DropMode.INSERT); list.setDragEnabled(true); // https://java-swing-tips.blogspot.com/2008/10/rubber-band-selection-drag-and-drop.html list.setLayoutOrientation(JList.HORIZONTAL_WRAP); list.setVisibleRowCount(0); list.setFixedCellWidth(80); list.setFixedCellHeight(80); list.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); list.setCellRenderer(new ListCellRenderer() { private final JPanel p = new JPanel(new BorderLayout()); private final JLabel icon = new JLabel((Icon)null, JLabel.CENTER); private final JLabel label = new JLabel("", JLabel.CENTER); @Override public Component getListCellRendererComponent( JList list, Thumbnail value, int index, boolean isSelected, boolean cellHasFocus) { icon.setIcon(value.icon); label.setText(value.name); label.setForeground(isSelected ? list.getSelectionForeground() : list.getForeground()); p.add(icon); p.add(label, BorderLayout.SOUTH); p.setBackground(isSelected ? list.getSelectionBackground() : list.getBackground()); return p; } }); return new JScrollPane(list); } public static void main(String[] args) { EventQueue.invokeLater(() -> createAndShowGUI()); } public static void createAndShowGUI() { JFrame f = new JFrame(); f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); f.getContentPane().add(new DragAndDropTest().makeUI()); f.setSize(320, 240); f.setLocationRelativeTo(null); f.setVisible(true); } } class Thumbnail implements Serializable { public final String name; public final Icon icon; public Thumbnail(String name) { this.name = name; this.icon = UIManager.getIcon("OptionPane." + name + "Icon"); } } // @camickr already suggested above. // https://docs.oracle.com/javase/tutorial/uiswing/dnd/dropmodedemo.html @SuppressWarnings("serial") class ListItemTransferHandler extends TransferHandler { protected final DataFlavor localObjectFlavor; protected int[] indices; protected int addIndex = -1; // Location where items were added protected int addCount; // Number of items added. public ListItemTransferHandler() { super(); // localObjectFlavor = new ActivationDataFlavor( // Object[].class, DataFlavor.javaJVMLocalObjectMimeType, "Array of items"); localObjectFlavor = new DataFlavor(Object[].class, "Array of items"); } @Override protected Transferable createTransferable(JComponent c) { JList source = (JList) c; c.getRootPane().getGlassPane().setVisible(true); indices = source.getSelectedIndices(); Object[] transferedObjects = source.getSelectedValuesList().toArray(new Object[0]); // return new DataHandler(transferedObjects, localObjectFlavor.getMimeType()); return new Transferable() { @Override public DataFlavor[] getTransferDataFlavors() { return new DataFlavor[] {localObjectFlavor}; } @Override public boolean isDataFlavorSupported(DataFlavor flavor) { return Objects.equals(localObjectFlavor, flavor); } @Override public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException { if (isDataFlavorSupported(flavor)) { return transferedObjects; } else { throw new UnsupportedFlavorException(flavor); } } }; } @Override public boolean canImport(TransferSupport info) { return info.isDrop() && info.isDataFlavorSupported(localObjectFlavor); } @Override public int getSourceActions(JComponent c) { Component glassPane = c.getRootPane().getGlassPane(); glassPane.setCursor(DragSource.DefaultMoveDrop); return MOVE; // COPY_OR_MOVE; } @SuppressWarnings("unchecked") @Override public boolean importData(TransferSupport info) { TransferHandler.DropLocation tdl = info.getDropLocation(); if (!canImport(info) || !(tdl instanceof JList.DropLocation)) { return false; } JList.DropLocation dl = (JList.DropLocation) tdl; JList target = (JList) info.getComponent(); DefaultListModel listModel = (DefaultListModel) target.getModel(); int max = listModel.getSize(); int index = dl.getIndex(); index = index < 0 ? max : index; // If it is out of range, it is appended to the end index = Math.min(index, max); addIndex = index; try { Object[] values = (Object[]) info.getTransferable().getTransferData(localObjectFlavor); for (int i = 0; i < values.length; i++) { int idx = index++; listModel.add(idx, values[i]); target.addSelectionInterval(idx, idx); } addCount = values.length; return true; } catch (UnsupportedFlavorException | IOException ex) { ex.printStackTrace(); } return false; } @Override protected void exportDone(JComponent c, Transferable data, int action) { c.getRootPane().getGlassPane().setVisible(false); cleanup(c, action == MOVE); } private void cleanup(JComponent c, boolean remove) { if (remove && Objects.nonNull(indices)) { if (addCount > 0) { // https://github.com/aterai/java-swing-tips/blob/master/DragSelectDropReordering/src/java/example/MainPanel.java for (int i = 0; i < indices.length; i++) { if (indices[i] >= addIndex) { indices[i] += addCount; } } } JList source = (JList) c; DefaultListModel model = (DefaultListModel) source.getModel(); for (int i = indices.length - 1; i >= 0; i--) { model.remove(indices[i]); } } indices = null; addCount = 0; addIndex = -1; } } 

请参阅DnD上的Swing教程中的Drop Demo ,以获取将放在同一JList或另一个JList上的示例。

正如OP在他们对原始问题的编辑中所指出的那样,给出的例子中的问题是有两个转移处理程序,并且在他们的答案中正确指出了camickr ,Java Tutorials中有一个例子可以使用。

Java教程中的示例的问题在于,当使用DropMode.INSERT并将当前JList的项目移动到所选索引之前时,该项目是重复的。 这将删除JList中的项目,将项目的副本放在您希望它去的位置,并保留原始选定项目。

因此,对于那些感兴趣的人,这里是一个基于OP问题中提供的JList示例修复该问题的示例。

 import java.awt.EventQueue; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.StringSelection; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.io.IOException; import javax.swing.DefaultListModel; import javax.swing.DropMode; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JList; import javax.swing.JScrollPane; import javax.swing.ListSelectionModel; import javax.swing.TransferHandler; @SuppressWarnings("serial") public class GUI extends JFrame { protected GUI() { super("Simple Rearrangeable List"); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); createPanel(); setBounds(10, 10, 350, 500); setVisible(true); } private void createPanel() { DefaultListModel strings = new DefaultListModel(); for(int i = 1; i <= 100; i++) { strings.addElement("Item " + i); } JList dndList = new JList(strings); dndList.setDragEnabled(true); dndList.setDropMode(DropMode.INSERT); dndList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); dndList.setTransferHandler(new TransferHandler() { private int index; private boolean beforeIndex = false; //Start with `false` therefore if it is removed from or added to the list it still works @Override public int getSourceActions(JComponent comp) { return MOVE; } @Override public Transferable createTransferable(JComponent comp) { index = dndList.getSelectedIndex(); return new StringSelection(dndList.getSelectedValue()); } @Override public void exportDone(JComponent comp, Transferable trans, int action) { if (action == MOVE) { if(beforeIndex) strings.remove(index + 1); else strings.remove(index); } } @Override public boolean canImport(TransferHandler.TransferSupport support) { return support.isDataFlavorSupported(DataFlavor.stringFlavor); } @Override public boolean importData(TransferHandler.TransferSupport support) { try { String s = (String) support.getTransferable().getTransferData(DataFlavor.stringFlavor); JList.DropLocation dl = (JList.DropLocation) support.getDropLocation(); strings.add(dl.getIndex(), s); beforeIndex = dl.getIndex() < index ? true : false; return true; } catch (UnsupportedFlavorException | IOException e) { e.printStackTrace(); } return false; } }); JScrollPane scrollPane = new JScrollPane(dndList); getContentPane().add(scrollPane); } public static void main(String[] args) { EventQueue.invokeLater(() -> new GUI()); } }