在Swing中的两个组件之间拖动

时间:2014-04-22 17:06:47

标签: java swing user-interface drag-and-drop mouseevent

我认为,我不是想拖延。我希望能够将标记从一个图形组件拖动到Swing中的相邻图形组件。我现在遇到的问题是,当我按住拖动时,MouseEvent的源字段始终设置为拖动开始的组件。鼠标进入和/或退出是否有办法让Swing停止在我拖动的Component上生成MouseEvents并开始在我当前正在拖动的Component上生成MouseEvents?

1 个答案:

答案 0 :(得分:2)

A couple of Swing components内置了对拖放的支持,这使得处理鼠标事件对于许多用例来说都是超级的。

这是一个在两个JLists之间一次来回移动一个或多个字符串的示例。在幕后,TransferHandler管理字符串的添加和删除。

以下示例基于thisthis

/**
 * The user can move list items between two lists using drag and drop
 * @author Matthias Braun
 *
 */
public class BidirectionalDragAndDrop extends JFrame {
    private static final long serialVersionUID = 1L;

    public BidirectionalDragAndDrop() {

        JList<String> source = createJListWithDragAndDrop();
        source.setModel(createSourceListModel());
        JList<String> target = createJListWithDragAndDrop();
        target.setModel(new DefaultListModel<String>());

        JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, source, target);
        JLabel label = new JLabel("You can drag the fruits from the left list to the right and vice versa");

        add(splitPane);
        add(label, BorderLayout.NORTH);
        setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        pack();
        setVisible(true);
    }

    private JList<String> createJListWithDragAndDrop() {
        JList<String> list = new JList<>();
        list.setDragEnabled(true);
        list.setDropMode(DropMode.INSERT);
        StringMoveHandler.createFor(list);

        return list;
    }

    private static DefaultListModel<String> createSourceListModel() {
        DefaultListModel<String> listModel = new DefaultListModel<>();
        for (String str : Arrays.asList("Papaya", "Orange", "Apple", "Mango", "Pear", "Avocado")) {
            listModel.addElement(str);
        }
        return listModel;
    }

    /**
     * Handles the moving of one or multiple strings between {@link JList}s.
     * 
     * @author Matthias Braun
     *
     */
    private static class StringMoveHandler extends TransferHandler {
        private static final long serialVersionUID = 1L;
        private DataFlavor objectArrayFlavor = new ActivationDataFlavor(Object[].class, DataFlavor.javaJVMLocalObjectMimeType, "Array of items");
        // We'll be moving the strings of this list
        private JList<String> list;

        // Clients should use a static factory method to instantiate the handler
        private StringMoveHandler() {
        };

        public static StringMoveHandler createFor(JList<String> list) {
            StringMoveHandler handler = new StringMoveHandler();
            list.setTransferHandler(handler);
            handler.list = list;
            return handler;
        }

        @Override
        public boolean canImport(TransferSupport info) {
            return info.isDataFlavorSupported(objectArrayFlavor);
        }

        @Override
        public boolean importData(TransferSupport transferSupport) {
            Transferable t = transferSupport.getTransferable();

            boolean success = false;
            try {
                Object[] importedData = (Object[]) t.getTransferData(objectArrayFlavor);
                addToListModel(importedData);
                success = true;
            }
            catch (UnsupportedFlavorException | IOException e) {
                e.printStackTrace();
            }
            return success;
        }

        private void addToListModel(Object[] importedData) {
            JList.DropLocation loc = list.getDropLocation();
            int dropIndex = loc.getIndex();

            DefaultListModel<String> listModel = (DefaultListModel<String>) list.getModel();
            for (int i = 0; i < importedData.length; i++) {
                Object elem = importedData[i];
                if (elem instanceof String) {
                    listModel.add(dropIndex + i, (String) elem);
                }
                else {
                    System.err.println("Imported data contained something else than strings: " + elem);
                }
            }
        }

        @Override
        public int getSourceActions(JComponent c) {
            return TransferHandler.COPY_OR_MOVE;
        }

        @Override
        public Transferable createTransferable(JComponent source) {
            // We need the values from the list as an object array, otherwise the data flavor won't match in importData
            @SuppressWarnings("deprecation")
            Object[] valuesToTransfer = list.getSelectedValues();
            return new DataHandler(valuesToTransfer, objectArrayFlavor.getMimeType());
        }

        @Override
        protected void exportDone(JComponent source, Transferable data, int action) {
            if (action == TransferHandler.MOVE) {
                try {
                    Object[] exportedData = (Object[]) data.getTransferData(objectArrayFlavor);
                    removeFromListModel(exportedData);
                }
                catch (UnsupportedFlavorException | IOException e) {
                    e.printStackTrace();
                }
            }
        }

        private void removeFromListModel(Object[] dataToRemove) {
            DefaultListModel<String> listModel = (DefaultListModel<String>) list.getModel();
            for (Object elemToRemove : dataToRemove) {
                boolean removedSuccessfully = listModel.removeElement(elemToRemove);
                if (!removedSuccessfully) {
                    System.err.println("Source model did not contain exported data");
                }
            }
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                    new BidirectionalDragAndDrop();
                }
                catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException e) {
                    e.printStackTrace();
                }
            }
        });
    }
}