使用TransferHandler拖动JLabel(拖放)

我正在使用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); } } 

另一个例子:

在此处输入图像描述

编辑:修复闪烁的光标

 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 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); } } 

更新:不幸的是,你正在使用TransferHandler

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

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

我做了一些挖掘,并且该类使用了一堆“私有”内部类来处理DnD进程的工作,使得几乎不可能简单地改变实现而不必重写整个事物。

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

我使用了这段代码并进行了一些修改。 我根据服务条款将其转发给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 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) { 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); } }