I have a problem with creating drag and drop in Swing. I have written class that represents the toolbar item here is the code shortened code for it:
public class ToolbarItem extends javax.swing.JToggleButton implements IToolbarItem, Transferable,
DragSourceListener, DragGestureListener {
private ModelEquivalent _modelEquivalent;
private DragSource _dragAndDropSource;
private TransferHandler _itemTransferHandler;
public ToolbarItem(ModelEquivalent modelEquivalent) {
this._modelEquivalent = modelEquivalent;
try {
this.initItemSettings();
} catch (java.io.IOException ex) {
System.out.println("Could not initialize toolbar item " + _modelEquivalent.toString());
}
}
private void initItemSettings() throws java.io.IOException {
initDragAndDropGestures();
}
private void initDragAndDropGestures() {
this._itemTransferHandler = new TransferHandler() {
@Override
public Transferable createTransferable(JComponent c) {
return new ToolbarItem(_modelEquivalent);
}
};
this.setTransferHandler(_itemTransferHandler);
this._dragAndDropSource = new DragSource();
_dragAndDropSource.createDefaultDragGestureRecognizer(this, DnDConstants.ACTION_COPY, this);
}
@Override
public ModelEquivalent getModelEquivalent() {
return _modelEquivalent;
}
@Override
public DataFlavor[] getTransferDataFlavors() {
return new DataFlavor[]{new DataFlavor(ToolbarItem.class, _modelEquivalent.toString())};
}
@Override
public boolean isDataFlavorSupported(DataFlavor flavor) {
return true;
}
@Override
public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
return this;
}
@Override
public void dragEnter(DragSourceDragEvent dsde) {
}
@Override
public void dragOver(DragSourceDragEvent dsde) {
}
@Override
public void dropActionChanged(DragSourceDragEvent dsde) {
}
@Override
public void dragExit(DragSourceEvent dse) {
}
@Override
public void dragDropEnd(DragSourceDropEvent dsde) {
}
@Override
public void dragGestureRecognized(DragGestureEvent dge) {
if (!this.isSelected()) {
this.setBorder(null);
_dragAndDropSource.startDrag(dge, DragSource.DefaultMoveDrop, new OnBoardItem(_modelEquivalent), this);
}
}
}
The thing is when the drag gesture is recognized I create the object of other class which is represented by this class:
public class OnBoardItem extends JLabel implements Transferable, DragSourceListener, DragGestureListener {
private static int _ID;
private DragSource _dragAndDropSource;
private TransferHandler _itemTransferHandler;
private ModelEquivalent _modelEquivalent;
public OnBoardItem(ModelEquivalent modelEquivalent) {
OnBoardItem._ID++;
this._modelEquivalent = modelEquivalent;
initDragAndDropGestures();
}
private void initDragAndDropGestures() {
this._itemTransferHandler = new TransferHandler() {
@Override
public Transferable createTransferable(JComponent c) {
return OnBoardItem.this;
}
};
this.setTransferHandler(_itemTransferHandler);
this._dragAndDropSource = new DragSource();
_dragAndDropSource.createDefaultDragGestureRecognizer(this, DnDConstants.ACTION_MOVE, this);
}
@Override
public DataFlavor[] getTransferDataFlavors() {
return new DataFlavor[]{new DataFlavor(OnBoardItem.class, _modelEquivalent.toString())};
}
@Override
public boolean isDataFlavorSupported(DataFlavor flavor) {
return true;
}
@Override
public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
return this;
}
@Override
public void dragEnter(DragSourceDragEvent dsde) {
}
@Override
public void dragOver(DragSourceDragEvent dsde) {
}
@Override
public void dropActionChanged(DragSourceDragEvent dsde) {
}
@Override
public void dragExit(DragSourceEvent dse) {
}
@Override
public void dragDropEnd(DragSourceDropEvent dsde) {
}
@Override
public void dragGestureRecognized(DragGestureEvent dge) {
_dragAndDropSource.startDrag(dge, DragSource.DefaultMoveDrop, this, this);
}
The last class which is the board class where I place dropped items:
public class DroppablePanel extends javax.swing.JPanel implements java.awt.dnd.DropTargetListener {
private java.util.ArrayList<OnBoardItem> _items;
private java.awt.dnd.DropTarget _target;
private static int _itemsCounter = 0;
public DroppablePanel() {
_items = new ArrayList<>();
_target = new DropTarget(this, this);
setTransferHandler(new ToolsItemHandler());
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (isOpaque()) {
g.setColor(getBackground());
g.fillRect(0, 0, getWidth(), getHeight());
}
}
@Override
public void dragEnter(DropTargetDragEvent dtde) {
}
@Override
public void dragOver(DropTargetDragEvent dtde) {
}
@Override
public void dropActionChanged(DropTargetDragEvent dtde) {
}
@Override
public void dragExit(DropTargetEvent dte) {
}
@Override
public void drop(DropTargetDropEvent dtde) {
try {
Point location = dtde.getLocation();
Transferable transferred = dtde.getTransferable();
DataFlavor[] transferredData = transferred.getTransferDataFlavors();
if (getTransferHandler().canImport(this, transferredData)) {
((ToolsItemHandler) getTransferHandler()).importData(this, (OnBoardItem) transferred.getTransferData(transferredData[0]), location);
repaint();
} else {
}
} catch (UnsupportedFlavorException | IOException ex) {
} finally {
dtde.dropComplete(true);
}
}
class ToolsItemHandler extends TransferHandler {
@Override
public boolean canImport(JComponent c, DataFlavor[] f) {
DataFlavor temp = new DataFlavor(OnBoardItem.class, "OnBoardItem");
for (DataFlavor d : f) {
if (d.equals(temp)) {
return true;
}
}
return false;
}
public boolean importData(JComponent comp, Transferable t, Point p) {
try {
OnBoardItem temporaryOnboardItem = (OnBoardItem) t.getTransferData(new DataFlavor(ToolbarItem.class, "OnBoardItem"));
System.out.println(getTransferHandler().getSourceActions(comp));
//OnBoardItem temp = new OnBoardItem(temporaryOnboardItem.getModelEquivalent());
if (_items.add(temporaryOnboardItem)) {
_itemsCounter++;
System.out.println(_items.size());
add(temporaryOnboardItem);
temporaryOnboardItem.setBounds((int) p.getX(), (int) p.getY(), 43, 43);
System.out.println("X: " + p.getX() + " Y: " + p.getY());
}
revalidate();
repaint();
} catch (UnsupportedFlavorException | IOException ex) {
}
return true;
}
}
}
So here is my problem: when I drag the object of a class ToolbarItem it creates the object of a class OnBoardItem which is placed on the DroppablePanel, the new object is added to the list and its all fine the main option is COPY in DnD that what I want, when I select the item that's been already placed on the DroppablePanel instead of moving the object to the different location it coppies it and place the same object in a different place, when all I want to do is just move them around on the panel. I know its because of a wrongly written TransferHandler in DroppablePanel, but I have spent hours trying to figure out how to fix this but nothing helped at all. If I would have to rewrite these classes or simplify them somehow please let me know how to do this the easiest way. Thanks in advance
EDIT: Graphical settings and methods of the classes have been cut to simplify the code.