如何在使用 Java Swing 复制到另一个列表时在列表内移动?

How to move inside a list while copy to another list with Java Swing ?

我有以下程序可以在 2 个列表之间复制或移动项目,我想以此为基础开发一个 DJ 程序来播放音乐。 右侧列表是从我 PC 上的目录读取的可用歌曲列表,左侧列表包含我要播放的歌曲。

所以当我从右到左拖放一首歌曲时,它会被添加到要播放的歌曲列表中,但是当我从左到右拖放一首歌曲时,它应该只是将它从列表中删除在左侧播放列表,同时不影响从本地驱动器读取的右侧列表中的歌曲列表。当我在左侧列表中 d&d 歌曲时,它只是重新排序播放列表,那么如何更改它以便:

[1] When I drag and drop an item in the left list, it moves the item inside the list
[2] When I drag and drop an item from the left list to the right list, it only removes it from left list while does nothing to the right list
[3] When I drag and drop an item from the right list to the left list, it only adds the item to the left list while does nothing to the right list.

import java.awt.*;
import java.awt.datatransfer.*;
import java.awt.event.ActionEvent;
import java.io.IOException;
import javax.activation.*;
import javax.swing.*;
import javax.swing.border.*;

public final class Demo_Drag_And_Drop_List_Panel extends JPanel                // http://ateraimemo.com/Swing/DnDBetweenLists.html
{
  static JRadioButton Copy_Button=new JRadioButton("Copy"),Move_Button=new JRadioButton("Move");

  private Demo_Drag_And_Drop_List_Panel()
  {
    super(new BorderLayout());
    JPanel p=new JPanel(new GridLayout(1,2,10,0));
    TransferHandler h=new ListItemTransferHandler();
    TitledBorder title=BorderFactory.createTitledBorder("Drag & Drop between JLists");
    p.setBorder(title);
    title.setTitleJustification(TitledBorder.CENTER);
    p.add(new JScrollPane(makeList(h)));
    p.add(new JScrollPane(makeList(h)));
    add(p);
    setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
    setPreferredSize(new Dimension(500,260));

    JPanel Copy_Or_Move_Option_Panel=new JPanel();

    Copy_Or_Move_Option_Panel.add(Copy_Button);

    Move_Button.setSelected(true);
    Copy_Or_Move_Option_Panel.add(Move_Button);

    //Group the radio buttons.
    ButtonGroup group=new ButtonGroup();
    group.add(Copy_Button);
    group.add(Move_Button);

    add("South",Copy_Or_Move_Option_Panel);
  }

  private static JList<Color> makeList(TransferHandler handler)
  {
    DefaultListModel<Color> listModel=new DefaultListModel<>();
    listModel.addElement(Color.RED);
    listModel.addElement(Color.BLUE);
    listModel.addElement(Color.GREEN);
    listModel.addElement(Color.CYAN);
    listModel.addElement(Color.ORANGE);
    listModel.addElement(Color.PINK);
    listModel.addElement(Color.MAGENTA);
    JList<Color> list=new JList<>(listModel);
    list.setCellRenderer(new DefaultListCellRenderer()
    {
      @Override public Component getListCellRendererComponent(JList list,Object value,int index,boolean isSelected,boolean cellHasFocus)
      {
        Component c=super.getListCellRendererComponent(list,value,index,isSelected,cellHasFocus);
        ((JLabel)c).setForeground((Color)value);
        return c;
      }
    });
    list.getSelectionModel().setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
    list.setDropMode(DropMode.INSERT);
    list.setDragEnabled(true);
    list.setTransferHandler(handler);

    ActionMap map=list.getActionMap();
    AbstractAction dummy=new AbstractAction()                                  // Disable row Cut, Copy, Paste
    {
      @Override public void actionPerformed(ActionEvent e)
      { /* Dummy action */ }
    };
    map.put(TransferHandler.getCutAction().getValue(Action.NAME),dummy);
    map.put(TransferHandler.getCopyAction().getValue(Action.NAME),dummy);
    map.put(TransferHandler.getPasteAction().getValue(Action.NAME),dummy);

    return list;
  }

  public static void createAndShowGUI()
  {
//    try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); }
//    catch (ClassNotFoundException|InstantiationException|IllegalAccessException|UnsupportedLookAndFeelException ex) { ex.printStackTrace(); }
    JFrame frame=new JFrame("Demo_Drag_And_Drop_List_Panel");
    frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    frame.getContentPane().add(new Demo_Drag_And_Drop_List_Panel());
    frame.pack();
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);
  }

  public static void main(String... args)
  {
    EventQueue.invokeLater(new Runnable()
    {
      @Override public void run() { createAndShowGUI(); }
    });
  }
}

class ListItemTransferHandler extends TransferHandler                          // Demo - BasicDnD (Drag and Drop and Data Transfer)>http://docs.oracle.com/javase/tutorial/uiswing/dnd/basicdemo.html
{
  private final DataFlavor localObjectFlavor;
  private JList source;
  private int[] indices;
  private int addIndex=-1;                                                     // Location where items were added
  private int addCount;                                                        // Number of items added.

  public ListItemTransferHandler()
  {
    super();
    localObjectFlavor=new ActivationDataFlavor(Object[].class,DataFlavor.javaJVMLocalObjectMimeType,"Array of items");
  }

  @Override protected Transferable createTransferable(JComponent c)
  {
    source=(JList)c;
    indices=source.getSelectedIndices();
    @SuppressWarnings("deprecation") Object[] transferedObjects=source.getSelectedValues();
    return new DataHandler(transferedObjects,localObjectFlavor.getMimeType());
  }

  @Override public boolean canImport(TransferSupport info) { return info.isDrop()&&info.isDataFlavorSupported(localObjectFlavor); }

  @Override public int getSourceActions(JComponent c)
  {
    return Demo_Drag_And_Drop_List_Panel.Copy_Button.isSelected()?COPY:MOVE;   // TransferHandler.COPY_OR_MOVE;
  }

  @SuppressWarnings("unchecked")
  @Override public boolean importData(TransferSupport info)
  {
    if (!canImport(info)) return false;
    TransferHandler.DropLocation tdl=info.getDropLocation();
    if (!(tdl instanceof JList.DropLocation)) return false;
    JList.DropLocation dl=(JList.DropLocation)tdl;
    JList target=(JList)info.getComponent();
    DefaultListModel listModel=(DefaultListModel)target.getModel();
    int index=dl.getIndex();
    //boolean insert = dl.isInsert();
    int max=listModel.getSize();
    if (index<0||index>max) 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=target.equals(source)?values.length:0;
      return true;
    }
    catch (UnsupportedFlavorException|IOException ex) { ex.printStackTrace(); }
    return false;
  }

  @Override protected void exportDone(JComponent c,Transferable data,int action) { cleanup(c,action==MOVE); }

  private void cleanup(JComponent c,boolean remove)
  {
    if (remove && indices!=null)
    {
      // If we are moving items around in the same list, we need to adjust the indices accordingly, since those after the insertion point have moved.
      if (addCount>0)
      {
        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;
  }
}

另一种选择是使用 Component#setName(String)Component#getName():

[2] When I drag and drop an item from the left list to the right list, it only removes it from left list while does nothing to the right list

if ("songs-right-list".equals(target.getName())
   && "play-left-list".equals(source.getName())) {
  return true;
}

[3] When I drag and drop an item from the right list to the left list, it only adds the item to the left list while does nothing to the right list.

if ("play-left-list".equals(target.getName())
    && "songs-right-list".equals(source.getName())) {
  indices = null;
}

DemoDragAndDropListPanel.java

import java.awt.*;
import java.awt.datatransfer.*;
import java.awt.event.ActionEvent;
import java.io.IOException;
import javax.activation.*;
import javax.swing.*;
import javax.swing.border.*;

public final class DemoDragAndDropListPanel extends JPanel                // http://ateraimemo.com/Swing/DnDBetweenLists.html
{
  static JRadioButton Copy_Button=new JRadioButton("Copy"),Move_Button=new JRadioButton("Move");

  private DemoDragAndDropListPanel()
  {
    super(new BorderLayout());
    JPanel p=new JPanel(new GridLayout(1,2,10,0));
    TransferHandler h=new ListItemTransferHandler();
    TitledBorder title=BorderFactory.createTitledBorder("Drag & Drop between JLists");
    p.setBorder(title);
    title.setTitleJustification(TitledBorder.CENTER);
    p.add(new JScrollPane(makeList("play-left-list", h)));
    p.add(new JScrollPane(makeList("songs-right-list", h)));
    add(p);
    setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
    setPreferredSize(new Dimension(500,260));

    JPanel Copy_Or_Move_Option_Panel=new JPanel();

    Copy_Or_Move_Option_Panel.add(Copy_Button);

    Move_Button.setSelected(true);
    Copy_Or_Move_Option_Panel.add(Move_Button);

    //Group the radio buttons.
    ButtonGroup group=new ButtonGroup();
    group.add(Copy_Button);
    group.add(Move_Button);

    add("South",Copy_Or_Move_Option_Panel);
  }

  private static JList<Color> makeList(String name, TransferHandler handler)
  {
    DefaultListModel<Color> listModel=new DefaultListModel<>();
    listModel.addElement(Color.RED);
    listModel.addElement(Color.BLUE);
    listModel.addElement(Color.GREEN);
    listModel.addElement(Color.CYAN);
    listModel.addElement(Color.ORANGE);
    listModel.addElement(Color.PINK);
    listModel.addElement(Color.MAGENTA);
    JList<Color> list=new JList<>(listModel);
    list.setName(name);
    list.setCellRenderer(new DefaultListCellRenderer()
    {
      @Override public Component getListCellRendererComponent(JList list,Object value,int index,boolean isSelected,boolean cellHasFocus)
      {
        Component c=super.getListCellRendererComponent(list,value,index,isSelected,cellHasFocus);
        ((JLabel)c).setForeground((Color)value);
        return c;
      }
    });
    list.getSelectionModel().setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
    list.setDropMode(DropMode.INSERT);
    list.setDragEnabled(true);
    list.setTransferHandler(handler);

    ActionMap map=list.getActionMap();
    AbstractAction dummy=new AbstractAction()                                  // Disable row Cut, Copy, Paste
    {
      @Override public void actionPerformed(ActionEvent e)
      { /* Dummy action */ }
    };
    map.put(TransferHandler.getCutAction().getValue(Action.NAME),dummy);
    map.put(TransferHandler.getCopyAction().getValue(Action.NAME),dummy);
    map.put(TransferHandler.getPasteAction().getValue(Action.NAME),dummy);

    return list;
  }

  public static void createAndShowGUI()
  {
//    try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); }
//    catch (ClassNotFoundException|InstantiationException|IllegalAccessException|UnsupportedLookAndFeelException ex) { ex.printStackTrace(); }
    JFrame frame=new JFrame("DemoDragAndDropListPanel");
    frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    frame.getContentPane().add(new DemoDragAndDropListPanel());
    frame.pack();
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);
  }

  public static void main(String... args)
  {
    EventQueue.invokeLater(new Runnable()
    {
      @Override public void run() { createAndShowGUI(); }
    });
  }
}

class ListItemTransferHandler extends TransferHandler                          // Demo - BasicDnD (Drag and Drop and Data Transfer)>http://docs.oracle.com/javase/tutorial/uiswing/dnd/basicdemo.html
{
  private final DataFlavor localObjectFlavor;
  private JList source;
  private int[] indices;
  private int addIndex=-1;                                                     // Location where items were added
  private int addCount;                                                        // Number of items added.

  public ListItemTransferHandler()
  {
    super();
    localObjectFlavor=new ActivationDataFlavor(Object[].class,DataFlavor.javaJVMLocalObjectMimeType,"Array of items");
  }

  @Override protected Transferable createTransferable(JComponent c)
  {
    source=(JList)c;
    indices=source.getSelectedIndices();
    @SuppressWarnings("deprecation") Object[] transferedObjects=source.getSelectedValues();
    return new DataHandler(transferedObjects,localObjectFlavor.getMimeType());
  }

  @Override public boolean canImport(TransferSupport info) { return info.isDrop()&&info.isDataFlavorSupported(localObjectFlavor); }

  @Override public int getSourceActions(JComponent c)
  {
    return DemoDragAndDropListPanel.Copy_Button.isSelected()?COPY:MOVE;   // TransferHandler.COPY_OR_MOVE;
  }

  @SuppressWarnings("unchecked")
  @Override public boolean importData(TransferSupport info)
  {
    if (!canImport(info)) return false;
    TransferHandler.DropLocation tdl=info.getDropLocation();
    if (!(tdl instanceof JList.DropLocation)) return false;
    JList.DropLocation dl=(JList.DropLocation)tdl;
    JList target=(JList)info.getComponent();
    DefaultListModel listModel=(DefaultListModel)target.getModel();
    int index=dl.getIndex();
    //boolean insert = dl.isInsert();
    int max=listModel.getSize();
    if (index<0||index>max) index=max;
    addIndex=index;

    if ("songs-right-list".equals(target.getName()) && "play-left-list".equals(source.getName())) {
      System.out.println("[2] When I drag and drop an item from the left list to the right list, it only removes it from left list while does nothing to the right list");
      return true;
    }
    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=target.equals(source)?values.length:0;
      if ("play-left-list".equals(target.getName()) && "songs-right-list".equals(source.getName())) {
        System.out.println("[3] When I drag and drop an item from the right list to the left list, it only adds the item to the left list while does nothing to the right list.");
        indices = null;
      }
      return true;
    }
    catch (UnsupportedFlavorException|IOException ex) { ex.printStackTrace(); }
    return false;
  }

  @Override protected void exportDone(JComponent c,Transferable data,int action) { cleanup(c,action==MOVE); }

  private void cleanup(JComponent c,boolean remove)
  {
    if (remove && indices!=null)
    {
      // If we are moving items around in the same list, we need to adjust the indices accordingly, since those after the insertion point have moved.
      if (addCount>0)
      {
        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;
  }
}