考虑documentation of TransferHandler.exportDone:
数据导出后调用。如果操作为MOVE,则此方法应删除传输的数据。
这应该回答这两个问题。首先,您确实有责任实现移动语义,其次,您应该只在action 的值为MOVE 时执行此操作。除了不适用于您的场景的其他传输类型的可能性,因为您不支持它们,它可能会以零操作调用,以允许在中止传输后进行清理。当不满足先决条件时,这甚至可能在 exportAsDrag 方法中发生。
如果您不想支持拖动到自身上,您可以暂时禁用放置目标,使用exportDone 方法重置属性。
例如
public class DragAndDropExample {
public static void main(String[] args) {
EventQueue.invokeLater(DragAndDropExample::init);
}
private static void init() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch(ReflectiveOperationException|UnsupportedLookAndFeelException ex) {}
try {
BufferedImage img = ImageIO.read(
new URL("https://cdn.sstatic.net/img/favicons-sprite32.png"));
img = img.getSubimage(0, 11844, 32, 32);
ICON = new ImageIcon(img);
} catch(IOException ex) {
ICON = UIManager.getIcon("OptionPane.errorIcon");
}
JFrame frame = new JFrame("Test");
Container c = frame.getContentPane();
final int gridWidth = 4, gridHeight = 4;
c.setLayout(new GridLayout(gridHeight, gridWidth, 4, 4));
for(int y = 0; y < gridHeight; y++) {
for(int x = 0; x < gridWidth; x++) {
create(x, y, c);
}
}
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
static Icon ICON;
static final MouseAdapter DRAG_INIT = new MouseAdapter() {
@Override public void mousePressed(MouseEvent e) {
var c = (JComponent) e.getSource();
var handler = c.getTransferHandler();
handler.exportAsDrag(c, e, TransferHandler.MOVE);
}
};
static final TransferHandler ICON_TRANSFER = new TransferHandler( "icon" ) {
@Override public void exportAsDrag(JComponent comp, InputEvent e, int action) {
comp.getDropTarget().setActive(false);
super.exportAsDrag(comp, e, action);
}
@Override public int getSourceActions(JComponent c) {
return MOVE;
}
@Override protected void exportDone(
JComponent source, Transferable data, int action) {
source.getDropTarget().setActive(true);
if (action == MOVE) {
((JLabel)source).setIcon(null);
}
}
};
private static void create(int x, int y, Container c) {
JLabel l = new JLabel("\u00a0");
if(x == 0 && y == 0) l.setIcon(ICON);
l.setBorder(BorderFactory.createLineBorder(Color.lightGray, 1));
l.setTransferHandler(ICON_TRANSFER);
l.addMouseListener(DRAG_INIT);
c.add(l);
}
}
如果你不想禁用它,你可以存储组件,检查源和目标是否相同,如this answer,但你应该在exportDone方法中将记住的组件设置为null , 以确保没有内存泄漏。