使用DnD在JPanel中移动和重新排序JLabel

时间:2014-10-09 22:04:14

标签: java swing drag-and-drop jlabel

我有一个我正在处理的程序,它接受输入名称并创建JLabel并将它们填充到ArrayList中。当用户单击“开始”按钮时,JLabel将填充在左侧JPanel中。我一直尝试使用DnD来允许用户拖动并重新排序左侧面板中的标签。到目前为止,我只能将文本从一个标签复制到另一个标签。我的目标是在列表中向上或向下拖动标签,并根据它在JPanel中放置的位置,使剩余的JLabel在面板中向上或向下移动。我在面板上使用FlowLayout,标签宽度足以创建垂直对齐。这是我的代码:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.TransferHandler;
import javax.swing.border.Border;


public class Gui extends JFrame {
/**
 * 
 */
private static final long serialVersionUID = 1L;
private ArrayList<JLabel> players = new ArrayList<JLabel>();
private ArrayList<JLabel> monsters = new ArrayList<JLabel>();
private JButton addPlayer = new JButton();
private JButton removePlayer = new JButton();
private JButton addMonster = new JButton();
private JButton removeMonster = new JButton();
private JTextField name = new JTextField();
private JPanel listPanel = new JPanel();
private JPanel buttonPanel = new JPanel();
private JButton encounter = new JButton();
private JButton begin = new JButton();
//private JButton remove;// = new JButton();
int x_pressed;
int y_pressed;


public Gui(){
    super("D&D Initiative");
    final Container container = getContentPane();
    container.setLayout(new FlowLayout()); //change to GridBagLayout
    container.setPreferredSize(new Dimension(800, 500));

    listPanel.setPreferredSize(new Dimension(600, 500));
    listPanel.setBackground(Color.BLUE);
    listPanel.setOpaque(true);
    buttonPanel.setPreferredSize(new Dimension(200,500));
    buttonPanel.setBackground(Color.GREEN);
    buttonPanel.setOpaque(true);

    Dimension size = new Dimension(190,30);

    name.setPreferredSize(new Dimension(190,30));
    addPlayer.setText("Add Player");
    removePlayer.setText("Remove Player");
    addPlayer.setPreferredSize(size);
    removePlayer.setPreferredSize(size);
    addMonster.setText("Add Monster");
    removeMonster.setText("Remove Monster");
    addMonster.setPreferredSize(size);
    removeMonster.setPreferredSize(size);
    begin.setText("Begin Encounter");
    begin.setPreferredSize(size);

    buttonPanel.add(name);
    buttonPanel.add(addPlayer);
    buttonPanel.add(addMonster);
    buttonPanel.add(removePlayer);
    buttonPanel.add(removeMonster);
    buttonPanel.add(begin);







    final Border paddingBorder = BorderFactory.createEmptyBorder(0,10,0,0);

    addPlayer.addActionListener(new ActionListener(){
        public void actionPerformed(ActionEvent e){
            if(name.getText().compareToIgnoreCase("") != 0){
            final JLabel temp=new JLabel();
            temp.setPreferredSize(new Dimension(590,50));
            temp.setText(name.getText());
            temp.setBackground(Color.GRAY);
            temp.setForeground(Color.WHITE);
            temp.setOpaque(true);
            temp.setLayout(new BorderLayout());
            temp.setBorder(BorderFactory.createCompoundBorder(null,paddingBorder));
            //bPane.setPreferredSize(new Dimension(100,temp.getHeight()));

            JButton remove = new JButton();
            remove.setText("Remove");
            remove.addActionListener(new ActionListener(){
                public void actionPerformed(ActionEvent e){
                    System.out.println("Count of listeners: " + ((JButton) e.getSource()).getActionListeners().length); //debugging
                    listPanel.remove(temp);
                    listPanel.revalidate();
                    System.out.println("remove");
                    listPanel.repaint();
                }
            });
            temp.add(remove, BorderLayout.EAST);


            MouseListener listener = new DragMouseAdapter();
            temp.setTransferHandler(new TransferHandler("text"));
            temp.addMouseListener(listener);



            players.add(temp);
            name.setText("");
            name.requestFocusInWindow();
            }else{
                //throw error
            }
        }
    });

    begin.addActionListener(new ActionListener(){
        public void actionPerformed(ActionEvent e){
            for(int i=0;i<players.size();i++){
                JLabel h = players.get(i);
                h.setMinimumSize(new Dimension(590,30));
                int s = container.getHeight()/players.size();
                if(s < 50){
                    h.setPreferredSize(new Dimension(590,listPanel.getHeight()/(players.size()+1)));
                }else{
                    h.setPreferredSize(new Dimension(590,30));
                }
                listPanel.add(h, new Integer(1), 0);
            }
            listPanel.revalidate();
        }
    });

    container.add(listPanel);
    container.add(buttonPanel);

    pack();     // pack the frame to fit the container inside
    setLocation(150, 150);  // set the location on the monitor
    setVisible(true);
    setResizable(false);

}


/**
 * @param args
 */
public static void main(String[] args) {
    // TODO Auto-generated method stub
    Gui application = new Gui();
    application.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}

}

//start of drag and drop

class DragMouseAdapter extends MouseAdapter {
  public void mousePressed(MouseEvent e) {
    JComponent c = (JComponent) e.getSource();
    TransferHandler handler = c.getTransferHandler();
    handler.exportAsDrag(c, e, TransferHandler.COPY);
    System.out.println(c);
  }
}

仍有一些事情来自不同的尝试(例如未使用的变量)。

1 个答案:

答案 0 :(得分:1)

考虑使用JList而不是创建自己的标签组件,这有很多简洁的功能,只会让你的生活更简单,比如拖放......

有关详细信息,请查看How to Use Lists

拖放是一个相当复杂的API,开始时可能会让人感到困惑,因为包含“传输API”并没有帮助,这只会增加混乱。

话虽如此,“转移API”正是您在这种情况下所寻找的......

Swapping

import java.awt.EventQueue;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import javax.activation.ActivationDataFlavor;
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.TransferHandler;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class DragList {

    public static void main(String[] args) {
        new DragList();
    }

    public DragList() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                DefaultListModel<String> listModel = new DefaultListModel<>();
                listModel.addElement("Clara    Holmes");
                listModel.addElement("Bill    Moss");
                listModel.addElement("Della    Reeves");
                listModel.addElement("Lloyd    Gross");
                listModel.addElement("Cecilia    Floyd");
                listModel.addElement("Delia    Cummings");
                listModel.addElement("Tommy    Benson");
                listModel.addElement("Kirk    Casey");
                listModel.addElement("Chester    Manning");
                listModel.addElement("Elsa    Chapman");
                JList namesList = new JList(listModel);
                namesList.setDragEnabled(true);
                namesList.setDropMode(DropMode.ON_OR_INSERT);
                namesList.setTransferHandler(new ListItemTransferHandler());

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new JScrollPane(namesList));
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class ListItemTransferHandler extends TransferHandler {

        private DataFlavor flavor;

        public ListItemTransferHandler() {
            super("ListMove");
            flavor = new ActivationDataFlavor(int[].class, DataFlavor.javaJVMLocalObjectMimeType, "List of values");
        }

        @Override
        protected Transferable createTransferable(JComponent c) {

            System.out.println("createTransferable");
            JList list = (JList) c;
            DefaultListModel<String> model = (DefaultListModel<String>) list.getModel();
            int[] selectedValues = list.getSelectedIndices();

            List<ValuePair> values = new ArrayList<>(selectedValues.length);
            for (int index : selectedValues) {
                values.add(new ValuePair(index, model.getElementAt(index)));
            }

            return new ListOfValues(values);
        }

        @Override
        public boolean canImport(TransferSupport support) {
            boolean canImport = support.isDrop() && support.isDataFlavorSupported(flavor);
            return canImport;
        }

        @Override
        public int getSourceActions(JComponent c) {
            return MOVE;
        }

        @Override
        public boolean importData(TransferSupport support) {

            boolean imported = false;
            if (canImport(support)) {

                JList target = (JList) support.getComponent();
                target.clearSelection();
                JList.DropLocation dl = (JList.DropLocation) support.getDropLocation();
                DefaultListModel<String> model = (DefaultListModel<String>) target.getModel();
                int addIndex = dl.getIndex();
                if (addIndex < 0 || addIndex >= model.size()) {
                    addIndex = model.size();
                }

                try {
                    List<ValuePair> values = (List<ValuePair>) support.getTransferable().getTransferData(flavor);
                    for (ValuePair vp : values) {
                        int index = vp.getIndex();
                        String value = model.get(index);
                        model.add(addIndex, value);
                        target.addSelectionInterval(addIndex, addIndex);
                        addIndex++;
                    }
                    imported = true;
                } catch (UnsupportedFlavorException | IOException ex) {
                    ex.printStackTrace();
                }

            }

            return imported;

        }

        @Override
        protected void exportDone(JComponent source, Transferable data, int action) {
            if (action == MOVE) {

                JList list = (JList) source;
                DefaultListModel<String> model = (DefaultListModel<String>) list.getModel();
                try {

                    // Get the list of values and sort in decending order
                    List<ValuePair> values = (List<ValuePair>) data.getTransferData(flavor);
                    Collections.sort(values, new Comparator<ValuePair>() {
                        @Override
                        public int compare(ValuePair o1, ValuePair o2) {
                            return o2.getIndex() - o1.getIndex();
                        }
                    });

                    // Loop through for each item...
                    for (ValuePair vp : values) {

                        // Get the "last known" index of the value...
                        String modelValue = model.get(vp.getIndex());
                        String value = vp.getValue();
                        int index = vp.getIndex();

                        // If the value no long resides at it's last location, we need to find it,
                        // we can't rely on contains, as there are two values of the same value...
                        if (modelValue != value) {

                            // Look behind us, only the length of the number of values that were previously selected...
                            int startIndex = Math.max(vp.getIndex() - values.size(), 0);
                            int endIndex = vp.getIndex();
                            index = getIndexFor(value, model, startIndex, endIndex);
                            if (index < 0) {

                                // Look forward, only the length of the number of values that were previously selected...
                                endIndex = Math.min(vp.getIndex() + values.size(), model.size() - 1);
                                startIndex = vp.getIndex();
                                index = getIndexFor(value, model, startIndex, endIndex);

                            }

                        }

                        if (index < 0) {

                            // We lost the item ??
                            throw new IOException("Missing value?");

                        } else {

                            model.remove(index);

                        }

                    }

                } catch (UnsupportedFlavorException | IOException ex) {
                    ex.printStackTrace();
                }

            }
        }

        protected int getIndexFor(String value, DefaultListModel<String> model, int startIndex, int endIndex) {

            while (model.get(startIndex) != value && startIndex <= endIndex) {
                startIndex++;
            }

            return model.get(startIndex) == value ? startIndex : -1;

        }

        public class ValuePair {

            private int index;
            private String value;

            public ValuePair(int index, String value) {
                this.index = index;
                this.value = value;
            }

            public int getIndex() {
                return index;
            }

            public String getValue() {
                return value;
            }

        }

        public class ListOfValues implements Transferable {

            private List<ValuePair> values;

            public ListOfValues(List<ValuePair> values) {
                this.values = values;
            }

            @Override
            public DataFlavor[] getTransferDataFlavors() {
                return new DataFlavor[]{flavor};
            }

            @Override
            public boolean isDataFlavorSupported(DataFlavor flavor) {
                return Arrays.asList(getTransferDataFlavors()).contains(flavor);
            }

            @Override
            public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
                return values;
            }

        }

    }

}

请查看Demo - BasicDnD以获取其他演示,以及有关传输API的更多信息。