此解决方案有效。首先要注意。
我没有使用TransferHandler API。我不喜欢它,它太严格了,但是那是个人的事情(它做什么,它做得很好),因此这可能无法满足您的期望。
我正在使用BorderLayout进行测试。如果要使用其他布局,则必须尝试弄清楚。DnD子系统确实提供有关鼠标点的信息(移动和放下时)。
那么我们需要什么:
DataFlavor。我选择这样做是因为它允许更多的限制
public class PanelDataFlavor extends DataFlavor {
// This saves me having to make lots of copies of the same thing
public static final PanelDataFlavor SHARED_INSTANCE = new PanelDataFlavor();
public PanelDataFlavor() {
super(JPanel.class, null);
}
}
可转让的。某种包装器,它用一堆DataFlavor(在我们的例子中是PanelDataFlavor)包装数据(我们的JPanel)
public class PanelTransferable implements Transferable {
private DataFlavor[] flavors = new DataFlavor[]{PanelDataFlavor.SHARED_INSTANCE};
private JPanel panel;
public PanelTransferable(JPanel panel) {
this.panel = panel;
}
@Override
public DataFlavor[] getTransferDataFlavors() {
return flavors;
}
@Override
public boolean isDataFlavorSupported(DataFlavor flavor) {
// Okay, for this example, this is overkill, but makes it easier
// to add new flavor support by subclassing
boolean supported = false;
for (DataFlavor mine : getTransferDataFlavors()) {
if (mine.equals(flavor)) {
supported = true;
break;
}
}
return supported;
}
public JPanel getPanel() {
return panel;
}
@Override
public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
Object data = null;
if (isDataFlavorSupported(flavor)) {
data = getPanel();
} else {
throw new UnsupportedFlavorException(flavor);
}
return data;
}
}
一个“ DragGestureListener”
为此,我创建了一个简单的DragGestureHandler,它使用“ JPanel”作为要拖动的内容。这使手势处理程序可以自我管理。
public class DragGestureHandler implements DragGestureListener, DragSourceListener {
private Container parent;
private JPanel child;
public DragGestureHandler(JPanel child) {
this.child = child;
}
public JPanel getPanel() {
return child;
}
public void setParent(Container parent) {
this.parent = parent;
}
public Container getParent() {
return parent;
}
@Override
public void dragGestureRecognized(DragGestureEvent dge) {
// When the drag begins, we need to grab a reference to the
// parent container so we can return it if the drop
// is rejected
Container parent = getPanel().getParent();
setParent(parent);
// Remove the panel from the parent. If we don't do this, it
// can cause serialization issues. We could overcome this
// by allowing the drop target to remove the component, but that's
// an argument for another day
parent.remove(getPanel());
// Update the display
parent.invalidate();
parent.repaint();
// Create our transferable wrapper
Transferable transferable