Java中从JButton拖放到JComponent

6

我在网上搜索了如何将JButton拖放到对象的示例,但我无法使其正常工作。

我的程序能够在我点击按钮时使用selectedobject.setField()方法更新一个字段。我希望能够通过拖动JButton来实现这一操作,而不是点击按钮。

该如何实现呢? 我找到了以下代码,并尝试将其放入我的代码中:

btn.setTransferHandler(new ImageHandler());
btn.addMouseListener(new MouseAdapter() {
    public void mousePressed(MouseEvent e) {
        JComponent c = (JComponent)e.getSource();
        TransferHandler handler = c.getTransferHandler();
        handler.exportAsDrag(c, e, TransferHandler.COPY);
    }
});

我从这里获取了ImageHandler类。


“gets a new value”是什么意思?你想把按钮的“值”拖到其他地方吗? - MadProgrammer
该按钮为所选对象添加动画。我希望能够通过拖放将同样的动画添加到随机对象中。 - user3450862
1个回答

16

拖放是一个有趣的袋子,里面有脆脆的胡萝卜...但这并不好,因为有一个“核心”API和更新的“传输”API,所以很容易混淆

以下示例使用“传输”API,并将String值从按钮传输到JLabel

拖动数字

import java.awt.Color;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;
import java.awt.dnd.DnDConstants;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.TransferHandler;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.CompoundBorder;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;

public class Test {

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

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

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

    public class TestPane extends JPanel {

        public TestPane() {
            setLayout(new GridLayout(1, 2));
            add(createLeftPanel());
            add(createRightPanel());

        }

        protected JPanel createLeftPanel() {
            JPanel panel = new JPanel(new GridBagLayout());
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridwidth = GridBagConstraints.REMAINDER;
            gbc.fill = GridBagConstraints.HORIZONTAL;
            gbc.weightx = 1;
            for (int index = 0; index < 10; index++) {
                JButton btn = new JButton(Integer.toString(index + 1));
                panel.add(btn, gbc);
                btn.setTransferHandler(new ValueExportTransferHandler(Integer.toString(index + 1)));

                btn.addMouseMotionListener(new MouseAdapter() {
                    @Override
                    public void mouseDragged(MouseEvent e) {
                        JButton button = (JButton) e.getSource();
                        TransferHandler handle = button.getTransferHandler();
                        handle.exportAsDrag(button, e, TransferHandler.COPY);
                    }
                });
            }
            return panel;
        }

        protected JPanel createRightPanel() {
            JPanel panel = new JPanel(new GridBagLayout());
            JLabel label = new JLabel("Drop in");
            label.setBorder(new CompoundBorder(new LineBorder(Color.DARK_GRAY), new EmptyBorder(20, 20, 20, 20)));
            label.setTransferHandler(new ValueImportTransferHandler());
            panel.add(label);
            return panel;
        }

    }

    public static class ValueExportTransferHandler extends TransferHandler {

        public static final DataFlavor SUPPORTED_DATE_FLAVOR = DataFlavor.stringFlavor;
        private String value;

        public ValueExportTransferHandler(String value) {
            this.value = value;
        }

        public String getValue() {
            return value;
        }

        @Override
        public int getSourceActions(JComponent c) {
            return DnDConstants.ACTION_COPY_OR_MOVE;
        }

        @Override
        protected Transferable createTransferable(JComponent c) {
            Transferable t = new StringSelection(getValue());
            return t;
        }

        @Override
        protected void exportDone(JComponent source, Transferable data, int action) {
            super.exportDone(source, data, action);
            // Decide what to do after the drop has been accepted
        }

    }

    public static class ValueImportTransferHandler extends TransferHandler {

        public static final DataFlavor SUPPORTED_DATE_FLAVOR = DataFlavor.stringFlavor;

        public ValueImportTransferHandler() {
        }

        @Override
        public boolean canImport(TransferHandler.TransferSupport support) {
            return support.isDataFlavorSupported(SUPPORTED_DATE_FLAVOR);
        }

        @Override
        public boolean importData(TransferHandler.TransferSupport support) {
            boolean accept = false;
            if (canImport(support)) {
                try {
                    Transferable t = support.getTransferable();
                    Object value = t.getTransferData(SUPPORTED_DATE_FLAVOR);
                    if (value instanceof String) {
                        Component component = support.getComponent();
                        if (component instanceof JLabel) {
                            ((JLabel) component).setText(value.toString());
                            accept = true;
                        }
                    }
                } catch (Exception exp) {
                    exp.printStackTrace();
                }
            }
            return accept;
        }
    }
}

我已经将TransferHandler分离成“拖动”和“放置”版本,但你不必这样做,也可以使用单个TransferHandler执行两个操作,这取决于你。
你需要修改ValueExportTransferHandler以接受不同的值,并相应地修改SUPPORTED_DATE_FLAVOR,但这些是基础知识。
你也可以参考从JList中拖放自定义对象到JLabel作为另一个示例...

有些地方出了问题。我的意思是,“exportAsDrag”不应该在每个拖动事件中都被调用,对吧?即使它在实践中可能有效。编辑:我刚刚运行了它。它可以工作,并且鼠标拖动方法由于某种原因只执行了一次,所以一切看起来都很好。 - Dreamspace President
@DreamspacePresident 为什么不行呢?exportAsDrag是在mouseDragged上被调用的,如果不是这个时候,那应该在什么时候被调用呢?顺便说一句,我想你可能想到的是mouseMoved ;) - MadProgrammer
因为exportAsDrag的文档中说“导致Swing拖放支持被启动。”和“在此调用返回时,传输不一定已经完成(即,该调用不会阻塞等待放置)。”这对我来说清楚地暗示着这个东西应该每次拖放只调用一次。但请参见我其他评论的编辑,一切似乎都很好。 - Dreamspace President

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接