【问题标题】:Dragging a JLabel with a TransferHandler (Drag and Drop)使用 TransferHandler 拖动 JLabel(拖放)
【发布时间】:2012-07-12 17:26:38
【问题描述】:

我正在使用 TransferHandler 将数据从 JPanel 传递到 JTextArea 作为 JLabel(单击左侧面板中的某处以创建要拖动的 JLabel)

数据传输工作正常,但我还想“显示”JLabel,因为它与鼠标指针一起被拖动。

如果你注释掉

dropLabel.setTransferHandler(new TransferHandler("text"));

dropLabel.getTransferHandler().exportAsDrag(dropLabel, e,
            TransferHandler.COPY);

你会看到我想要的样子。 (但当然数据不会被传输)。

如何让传输工作和 JLabel 跟随鼠标光标?

代码如下:

import java.awt.*;
import java.awt.datatransfer.Transferable;
import java.awt.event.*;

import javax.swing.*;
import javax.swing.border.Border;

public class DragTest extends JFrame implements MouseMotionListener,
        MouseListener {

    private JPanel leftPanel = new JPanel(null);
    private JPanel rightPanel = new JPanel(null);
    private JLabel dragLabel = new JLabel("drop");
    private final JWindow window = new JWindow();
    JLabel dropLabel;

    public DragTest() {
        this.setLayout(new GridLayout(1, 2));

        leftPanel.setBorder(BorderFactory.createLineBorder(Color.black));
        rightPanel.setBorder(BorderFactory.createLineBorder(Color.black));
        this.add(leftPanel);
        this.add(rightPanel);
        leftPanel.addMouseListener(this);
        leftPanel.addMouseMotionListener(this);

        JTextArea area = new JTextArea();

        rightPanel.setLayout(new GridLayout(1, 1));
        rightPanel.add(area);

        dragLabel.setFont(new Font("Serif", Font.BOLD, 48));
    }

    @Override
    public void mousePressed(MouseEvent e) {

        dropLabel = new JLabel("drop");

        Dimension labelSize = dropLabel.getPreferredSize();
        dropLabel.setSize(labelSize);
        int x = e.getX() - labelSize.width / 2;
        int y = e.getY() - labelSize.height / 2;
        dropLabel.setLocation(x, y);
        leftPanel.add(dropLabel);

        dropLabel.setTransferHandler(new TransferHandler("text"));

        dropLabel.getTransferHandler().exportAsDrag(dropLabel, e,
                TransferHandler.COPY);

        repaint();

    }

    @Override
    public void mouseDragged(MouseEvent me) {
        dragLabel = new JLabel("drop");
        dragLabel.setFont(new Font("Serif", Font.BOLD, 48));
        int x = me.getPoint().x;
        int y = me.getPoint().y;
        window.add(dragLabel);
        window.pack();
        Point pt = new Point(x, y);
        Component c = (Component) me.getSource();
        SwingUtilities.convertPointToScreen(pt, c);
        window.setLocation(pt);
        window.setVisible(true);
        repaint();
    }

    @Override
    public void mouseMoved(MouseEvent e) {
    }

    @Override
    public void mouseClicked(MouseEvent e) {

    }

    @Override
    public void mouseReleased(MouseEvent e) {

//      leftPanel.remove(dropLabel);

        window.remove(dragLabel);
        window.setVisible(false);

        repaint();
    }

    @Override
    public void mouseEntered(MouseEvent e) {

    }

    @Override
    public void mouseExited(MouseEvent e) {

    }

    public static void main(String[] args) {

        DragTest frame = new DragTest();
        frame.setVisible(true);
        frame.setSize(600, 400);
        frame.setResizable(false);
        frame.setLocationRelativeTo(null);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }
}

【问题讨论】:

    标签: java swing drag-and-drop jpanel


    【解决方案1】:

    另一个例子:

    编辑:修复闪烁的光标

    import java.awt.*;
    import java.awt.datatransfer.*;
    import java.awt.dnd.*;
    import java.awt.event.*;
    import java.io.*;
    import java.util.*;
    import javax.activation.*;
    import javax.swing.*;
    import javax.swing.text.*;
    
    public class DragTest3 {
      public JComponent makeUI() {
        DragPanel p1 = new DragPanel();
        p1.setBorder(BorderFactory.createLineBorder(Color.BLACK));
        p1.add(new JLabel(UIManager.getIcon("OptionPane.warningIcon")));
        p1.add(new JLabel(UIManager.getIcon("OptionPane.errorIcon")));
        p1.add(new JLabel("Label1"));
        p1.add(new JLabel("Label2"));
        MouseListener handler = new Handler();
        p1.addMouseListener(handler);
        LabelTransferHandler th = new LabelTransferHandler();
        p1.setTransferHandler(th);
        JPanel p = new JPanel(new GridLayout(1,2));
        p.add(p1);
    
        DragPanel p2 = new DragPanel();
        p2.setBorder(BorderFactory.createLineBorder(Color.BLACK));
        p2.addMouseListener(handler);
        p2.setTransferHandler(th);
        p.add(p2);
    
        JPanel panel = new JPanel(new GridLayout(2,1));
        panel.add(p);
        panel.add(new JScrollPane(new JTextArea()));
        return panel;
      }
      public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
          @Override public void run() {
            createAndShowGUI();
          }
        });
      }
      public static void createAndShowGUI() {
        JFrame f = new JFrame();
        f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        f.getContentPane().add(new DragTest3().makeUI());
        f.setSize(320, 240);
        f.setLocationRelativeTo(null);
        f.setVisible(true);
      }
    }
    class DragPanel extends JPanel {
      public DragPanel() {
        super();
      }
      public JLabel draggingLabel;
    }
    class Handler extends MouseAdapter {
      @Override public void mousePressed(MouseEvent e) {
        DragPanel p = (DragPanel)e.getSource();
        Component c = SwingUtilities.getDeepestComponentAt(p, e.getX(), e.getY());
        if(c!=null && c instanceof JLabel) {
          p.draggingLabel = (JLabel)c;
          p.getTransferHandler().exportAsDrag(p, e, TransferHandler.MOVE);
        }
      }
    }
    class LabelTransferHandler extends TransferHandler {
      private final DataFlavor localObjectFlavor;
      private final JLabel label = new JLabel() {
        @Override public boolean contains(int x, int y) {
          return false;
        }
      };
      private final JWindow window = new JWindow();
      public LabelTransferHandler() {
        System.out.println("LabelTransferHandler");
        localObjectFlavor = new ActivationDataFlavor(
          DragPanel.class, DataFlavor.javaJVMLocalObjectMimeType, "JLabel");
        window.add(label);
        window.setAlwaysOnTop(true);
        window.setBackground(new Color(0,true));
        DragSource.getDefaultDragSource().addDragSourceMotionListener(
        new DragSourceMotionListener() {
          @Override public void dragMouseMoved(DragSourceDragEvent dsde) {
            Point pt = dsde.getLocation();
            pt.translate(5, 5); // offset
            window.setLocation(pt);
          }
        });
      }
      @Override protected Transferable createTransferable(JComponent c) {
        System.out.println("createTransferable");
        DragPanel p = (DragPanel)c;
        JLabel l = p.draggingLabel;
        String text = l.getText();
        //TEST
        //if(text==null) {
        //    text = l.getIcon().toString();
        //}
        //return new StringSelection(text+"\n");
        final DataHandler dh = new DataHandler(c, localObjectFlavor.getMimeType());
        if(text==null) return dh;
        final StringSelection ss = new StringSelection(text+"\n");
        return new Transferable() {
          @Override public DataFlavor[] getTransferDataFlavors() {
            ArrayList<DataFlavor> list = new ArrayList<>();
            for(DataFlavor f:ss.getTransferDataFlavors()) {
              list.add(f);
            }
            for(DataFlavor f:dh.getTransferDataFlavors()) {
              list.add(f);
            }
            return list.toArray(dh.getTransferDataFlavors());
          }
          public boolean isDataFlavorSupported(DataFlavor flavor) {
            for (DataFlavor f: getTransferDataFlavors()) {
              if (flavor.equals(f)) {
                return true;
              }
            }
            return false;
          }
          public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
            if(flavor.equals(localObjectFlavor)) {
              return dh.getTransferData(flavor);
            } else {
              return ss.getTransferData(flavor);
            }
          }
        };
      }
      @Override public boolean canImport(TransferSupport support) {
        if(!support.isDrop()) {
          return false;
        }
        return true;
      }
      @Override public int getSourceActions(JComponent c) {
        System.out.println("getSourceActions");
        DragPanel p = (DragPanel)c;
        label.setIcon(p.draggingLabel.getIcon());
        label.setText(p.draggingLabel.getText());
        window.pack();
        Point pt = p.draggingLabel.getLocation();
        SwingUtilities.convertPointToScreen(pt, p);
        window.setLocation(pt);
        window.setVisible(true);
        return MOVE;
      }
      @Override public boolean importData(TransferSupport support) {
        System.out.println("importData");
        if(!canImport(support)) return false;
        DragPanel target = (DragPanel)support.getComponent();
        try {
          DragPanel src = (DragPanel)support.getTransferable().getTransferData(localObjectFlavor);
          JLabel l = new JLabel();
          l.setIcon(src.draggingLabel.getIcon());
          l.setText(src.draggingLabel.getText());
          target.add(l);
          target.revalidate();
          return true;
        } catch(UnsupportedFlavorException ufe) {
          ufe.printStackTrace();
        } catch(java.io.IOException ioe) {
          ioe.printStackTrace();
        }
        return false;
      }
      @Override protected void exportDone(JComponent c, Transferable data, int action) {
        System.out.println("exportDone");
        DragPanel src = (DragPanel)c;
        if(action == TransferHandler.MOVE) {
          src.remove(src.draggingLabel);
          src.revalidate();
          src.repaint();
        }
        src.draggingLabel = null;
        window.setVisible(false);
      }
    }
    

    【讨论】:

    • @MadProgrammer 我也这么认为:)
    • 啊,是的,但这是一个不错的作弊方法;)
    • 这看起来很痛苦。没有文件或解释你做了什么。只有 200 行意大利面条式代码。
    【解决方案2】:

    更新:不幸的是,您使用的是TransferHandler

    我上次使用TransferHandler API(大约在 6.10/6.12 左右)时,代码中有一个错误,它忽略了传输图像。它实际上将其设置为空。这可能已在以后的更新中修复,但我最近没有检查过。

    经过大量挖掘,我发现 TransferHandler 的默认实现忽略了“getVisualRepresentation(Transferable t)”方法。不是很好。

    我做了一些挖掘,该类使用了一堆“私有”内部类来处理 DnD 过程的工作,这使得几乎不可能简单地更改实现而无需重写整个事情。

    基本上,DragSource 允许您传入它可以使用的图像(至于这是否可行是另一个问题),但它隐藏在私有 DragHandler 类中。谢谢孙。

    【讨论】:

    • 并尝试重写传输处理程序,但是有这么多包私有代码,这不是一个简单的任务
    • 我尝试了“手动”DnD 过程,并且“startDrag”方法不使用我在 Windows 7 下提供的拖动图像(我认为 Mac 可以做到这一点)......你可能想看看rabbit-hole.blogspot.com.au/2006/05/… 了解更多信息
    【解决方案3】:

    我使用了这段代码并做了一些修改。我根据 TOS 将其转发给 SO。

    import java.awt.Color;
    import java.awt.Point;
    import java.awt.datatransfer.DataFlavor;
    import java.awt.datatransfer.StringSelection;
    import java.awt.datatransfer.Transferable;
    import java.awt.datatransfer.UnsupportedFlavorException;
    import java.awt.dnd.DragSource;
    import java.awt.dnd.DragSourceDragEvent;
    import java.awt.dnd.DragSourceMotionListener;
    import java.io.IOException;
    import java.util.ArrayList;
    import javax.activation.ActivationDataFlavor;
    import javax.activation.DataHandler;
    import javax.swing.*;
    
    
    @SuppressWarnings("serial")
    public class LabelTransferHandler extends TransferHandler {
    
        private final DataFlavor localObjectFlavor;
        private final DeviceAssignments root;
    
        private final JLabel label = new JLabel() {
            @Override public boolean contains(int x, int y) {
                return false;
            }
        };
    
        private final JWindow window = new JWindow();
    
        public LabelTransferHandler(DeviceAssignments root) {
            this.root = root;
            localObjectFlavor = new ActivationDataFlavor(
                LabelDragScrollPane.class, DataFlavor.javaJVMLocalObjectMimeType, "JLabel");
            window.add(label);
            window.setAlwaysOnTop(true);
            window.setBackground(new Color(0,true));
            DragSource.getDefaultDragSource().addDragSourceMotionListener(
                new DragSourceMotionListener() {
                    @Override public void dragMouseMoved(DragSourceDragEvent dsde) {
                        Point pt = dsde.getLocation();
                        pt.translate(5, 5); // offset
                        window.setLocation(pt);
                    }
                }
            );
        }
    
        @Override protected Transferable createTransferable(JComponent c) {
            LabelDragScrollPane p = (LabelDragScrollPane)c;
            MacLabel l = p.draggingLabel;
            String text = l.getMac();
            final DataHandler dh = new DataHandler(c, localObjectFlavor.getMimeType());
            if(text==null) return dh;
            final StringSelection ss = new StringSelection(text+"\n");
            return new Transferable() {
                @Override public DataFlavor[] getTransferDataFlavors() {
                ArrayList<DataFlavor> list = new ArrayList<DataFlavor>();
                for(DataFlavor f:ss.getTransferDataFlavors()) {
                    list.add(f);
                }
                for(DataFlavor f:dh.getTransferDataFlavors()) {
                    list.add(f);
                }
                return list.toArray(dh.getTransferDataFlavors());
                }
                public boolean isDataFlavorSupported(DataFlavor flavor) {
                    for (DataFlavor f: getTransferDataFlavors()) {
                        if (flavor.equals(f)) {
                            return true;
                        }
                    }
                    return false;
                }
                public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
                    if(flavor.equals(localObjectFlavor)) {
                        return dh.getTransferData(flavor);
                    } else {
                        return ss.getTransferData(flavor);
                    }
                }
            };
        }
    
        @Override public boolean canImport(TransferSupport support) {
            if(!support.isDrop()) {
                return false;
            }
            return true;
        }
    
        @Override public int getSourceActions(JComponent c) {
            LabelDragScrollPane p = (LabelDragScrollPane)c;
            label.setBorder(p.draggingLabel.getBorder());
            label.setText(p.draggingLabel.getMac());
            label.setPreferredSize(p.draggingLabel.getPreferredSize());
    
            window.pack();
            Point pt = p.draggingLabel.getLocation();
            SwingUtilities.convertPointToScreen(pt, p);
            window.setLocation(pt);
            window.setVisible(true);
            return MOVE;
        }
    
        @Override public boolean importData(TransferSupport support) {
            if(!canImport(support)) return false;
            JButton target = (JButton)support.getComponent();
            try {
                LabelDragScrollPane src = (LabelDragScrollPane)support.getTransferable().getTransferData(localObjectFlavor);
                target.setText(src.draggingLabel.getMac());
                return true;
            } catch(UnsupportedFlavorException ufe) {
                ufe.printStackTrace();
            } catch(java.io.IOException ioe) {
                ioe.printStackTrace();
            }
            return false;
        }
        @Override protected void exportDone(JComponent c, Transferable data, int action) {
            LabelDragScrollPane src = (LabelDragScrollPane)c;
            if(action == TransferHandler.MOVE) {
                root.updateNodeIdPanel();
            }
            src.draggingLabel = null;
            window.setVisible(false);
        }
    }
    

    【讨论】:

    • 这似乎不是问题的新答案,可能会被删除。如果您正在重用代码并且担心 CC 许可,那么您需要向原作者询问其他许可或发布属性您在哪里使用它,而不是在这里。
    • 随心所欲。我遵循了网站的使用条款。我的良心很干净。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-25
    • 1970-01-01
    相关资源
    最近更新 更多