Arrastar e soltar o object personalizado do JList para o JLabel

Eu tenho um JList contendo uma ArrayList de objects personalizados e estou tentando criar um arrastar e soltar em campos. Estou tendo problemas para entender como empacotar e receber o object em Transferível.

Isso é o mais que eu consegui:

import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.event.*; import java.util.*; public class FlightProjectInterface extends JFrame{ //create GUI Objects private JFrame primaryFrame; private JPanel createFlightPanel; private JPanel aircraftLayout; private JList personsJList, personsOnFlightJList; private JTextField pilotLabel, coPilotLabel, backseat1Label, backseat2Label; public FlightProjectInterface(){ //establish frame super("Create Flight"); setLayout( new FlowLayout()); //aircraftPanel aircraftLayout = new JPanel(); aircraftLayout.setLayout(new GridLayout(2,2)); pilotLabel = new JTextField("Drag Pilot Here"); //build person load list DefaultListModel listModel = new DefaultListModel(); for (Person person : Database.persons) listModel.addElement(person); personsJList = new JList(listModel); personsJList.setVisibleRowCount(5); personsJList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); personsJList.setDragEnabled(true); add( new JScrollPane(personsJList) ); aircraftLayout.add(pilotLabel); add(aircraftLayout); }//end constructor } 

Esclarecimento: Estou com problemas para tirar a seleção de objects do JList e criar um Transferível para fora dele. Com o código acima, a representação toString do object é simplesmente colada no campo de texto, portanto, não consigo extrair dados de objects do local descartado. Como posso “empacotar” o object em si e soltá-lo em um marcador de posição que eu possa referenciar o próprio object da GUI?

Idealmente, haveria 4 campos que cada um contém um object que pode ser descartado. A pessoa seria removida da lista se ela for descartada, mas retornada à lista se for substituída.

Arrastar e soltar pode ser uma fera complexa, não facilitada pelas informações conflitantes disponíveis. Pessoalmente, eu gosto de evitar a API de transferência, mas eu sou da velha escola assim.

A cola para DataFlavor é realmente o DataFlavor . Eu prefiro fazer o meu próprio, torna a vida muito mais fácil.

Neste exemplo, eu usei um único TransferHandler , mas, realisticamente, você deve ter um para arrastar e outro para soltar, em particular, você deve ter um para cada componente que você quer colocar.

A principal razão para isso é, eu coloquei uma armadilha no meu método canImport para rejeitá-lo se você arrastar um JList , então você só pode soltá-lo no JLabel , isso é um pequeno hack e provavelmente não é a melhor idéia.

 import java.awt.BorderLayout; import java.awt.Component; import java.awt.EventQueue; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.awt.dnd.DnDConstants; import java.io.IOException; import javax.swing.DefaultListModel; 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.TransferHandler; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; public class DnDTransferableTest { public static void main(String[] args) { new DnDTransferableTest(); } public DnDTransferableTest() { 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); } }); } @SuppressWarnings("serial") public class TestPane extends JPanel { private JList list; private JLabel label; public TestPane() { list = new JList(); list.setDragEnabled(true); list.setTransferHandler(new ListTransferHandler()); DefaultListModel model = new DefaultListModel(); for (int index = 0; index < 10; index++) { model.addElement(new ListItem("Item " + index)); } list.setModel(model); setLayout(new GridBagLayout()); GridBagConstraints gbc = new GridBagConstraints(); gbc.gridx = 0; gbc.gridy = 0; gbc.weighty = 1; gbc.weightx = 1; gbc.fill = GridBagConstraints.BOTH; add(new JScrollPane(list), gbc); label = new JLabel("Drag on me..."); gbc.gridx++; gbc.weightx = 1; gbc.fill = GridBagConstraints.NONE; add(label, gbc); label.setTransferHandler(new ListTransferHandler()); } } @SuppressWarnings("serial") public class ListTransferHandler extends TransferHandler { @Override public boolean canImport(TransferSupport support) { return (support.getComponent() instanceof JLabel) && support.isDataFlavorSupported(ListItemTransferable.LIST_ITEM_DATA_FLAVOR); } @Override public boolean importData(TransferSupport support) { boolean accept = false; if (canImport(support)) { try { Transferable t = support.getTransferable(); Object value = t.getTransferData(ListItemTransferable.LIST_ITEM_DATA_FLAVOR); if (value instanceof ListItem) { Component component = support.getComponent(); if (component instanceof JLabel) { ((JLabel)component).setText(((ListItem)value).getText()); accept = true; } } } catch (Exception exp) { exp.printStackTrace(); } } return accept; } @Override public int getSourceActions(JComponent c) { return DnDConstants.ACTION_COPY_OR_MOVE; } @Override protected Transferable createTransferable(JComponent c) { Transferable t = null; if (c instanceof JList) { @SuppressWarnings("unchecked") JList list = (JList) c; Object value = list.getSelectedValue(); if (value instanceof ListItem) { ListItem li = (ListItem) value; t = new ListItemTransferable(li); } } return t; } @Override protected void exportDone(JComponent source, Transferable data, int action) { System.out.println("ExportDone"); // Here you need to decide how to handle the completion of the transfer, // should you remove the item from the list or not... } } public static class ListItemTransferable implements Transferable { public static final DataFlavor LIST_ITEM_DATA_FLAVOR = new DataFlavor(ListItem.class, "java/ListItem"); private ListItem listItem; public ListItemTransferable(ListItem listItem) { this.listItem = listItem; } @Override public DataFlavor[] getTransferDataFlavors() { return new DataFlavor[]{LIST_ITEM_DATA_FLAVOR}; } @Override public boolean isDataFlavorSupported(DataFlavor flavor) { return flavor.equals(LIST_ITEM_DATA_FLAVOR); } @Override public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException { return listItem; } } public static class ListItem { private String text; public ListItem(String text) { this.text = text; } public String getText() { return text; } @Override public String toString() { return getText(); } } }