1

After researching how to use Label DnD I come across with using this solution:

 public class LayerItem extends JLabel {
    int x = 0, y = 0;

    public LayerItem(String text) {
        this.setText(text);
        this.addMouseMotionListener(new MouseAdapter(){
            @Override
            public void mouseDragged(MouseEvent evt){
                lblMouseDragged(evt);
            }
        });
    }

    protected void lblMouseDragged(MouseEvent evt){
        this.x = evt.getX();
        this.y = evt.getY();
    }
}

As the user clicks, and holds, the JLabel the X and Y are recorded as the mouse moves. However, I am stuck on how to know when the click is stopped (ie, user reaches his targeted JPanel) to then move the text into it.

The only bit of reference to allowing JPanels to receive a drop action is by doing something like this:

new JPanel().setDropTarget(getDropTarget());

However, I cannot again find any references on passing through the JLabel as the drop target with the Coords (Absolute layout).

c0der
  • 18,467
  • 6
  • 33
  • 65
Jaquarh
  • 6,493
  • 7
  • 34
  • 86
  • 3
    Basically, your example won't work, it's not doing what you think it is. Instead, maybe have a look at [this example](https://stackoverflow.com/questions/22161412/java-drop-and-drag-label-to-join-correct-image/22161571#22161571) or [this example](https://stackoverflow.com/questions/28844574/drag-and-drop-from-jbutton-to-jcomponent-in-java/28844969#28844969) - basically anything make use of `Transferable` – MadProgrammer Oct 06 '18 at 09:52
  • 3
    And because this doesn't get asked often ... [this example](https://stackoverflow.com/questions/47253790/custom-deletion-container-for-transferable-and-transferhandler-on-jlist/47254491#47254491), [this example](https://stackoverflow.com/questions/11201734/java-how-to-drag-and-drop-jpanel-with-its-components/11443501#11443501), [this example](https://stackoverflow.com/questions/13855184/drag-and-drop-custom-object-from-jlist-into-jlabel/13856193#13856193)... – MadProgrammer Oct 06 '18 at 10:08
  • 3
    [this example](https://stackoverflow.com/questions/36590276/is-it-possible-to-start-drag-on-mousepressed-using-java-swing-dnd-api/36591691#36591691), [this example](https://stackoverflow.com/questions/26621830/jlayeredpanel-layout-manager-free-moving-objects/26624184#26624184), [this example](https://stackoverflow.com/questions/15520610/java-drag-and-drop/15521421#15521421), [this example](https://stackoverflow.com/questions/30429648/temporarily-disable-or-prevent-repainting-jviewport-on-scrolling-with-a-mousedra/30429965#30429965) – MadProgrammer Oct 06 '18 at 10:09
  • 3
    And because you should always consult the source [Drag and Drop and Data Transfer](https://docs.oracle.com/javase/tutorial/uiswing/dnd/index.html) – MadProgrammer Oct 06 '18 at 10:10
  • Thankyou for all these examples, currently trying to build it using them and ill post my result as an answer when I solve it! :) @MadProgrammer – Jaquarh Oct 06 '18 at 10:12
  • 2
    Drag'n'Drop is very complex, but it follows some basic rules, which, if you can get your head around them, make it a very flexible and powerful API – MadProgrammer Oct 06 '18 at 10:16
  • @MadProgrammer I have answered my question, thanks for the help! I also though about adding my own handlers to each container, so different containers will do different things when the items are dragged in – Jaquarh Oct 06 '18 at 10:37

1 Answers1

4

After looking at a few examples posted by @MadProgrammer I came up with a solution that extends both the JPanel and JLabel. Here is the JLabel class:

public class LayerItem extends JLabel {

    public LayerItem(String text) {

        this.setText(text);

        this.setTransferHandler(new ValueExportTransferHandler(text));

        this.addMouseMotionListener(new MouseAdapter() {
            @Override
            public void mouseDragged(MouseEvent e) {
                JLabel lbl = (JLabel) e.getSource();
                TransferHandler handle = lbl.getTransferHandler();
                handle.exportAsDrag(lbl, e, TransferHandler.COPY);
            }
        });

    }

    protected static class ValueExportTransferHandler extends TransferHandler {

        public static final DataFlavor SUPPORTED_DATE_FLAVOR = DataFlavor.stringFlavor;
        private String value;

        public ValueExportTransferHandler(String value) {
            this.value = value;
        }

        public String getValue() {
            return value;
        }

        @Override
        public int getSourceActions(JComponent c) {
            return DnDConstants.ACTION_COPY_OR_MOVE;
        }

        @Override
        protected Transferable createTransferable(JComponent c) {
            Transferable t = new StringSelection(getValue());
            return t;
        }

        @Override
        protected void exportDone(JComponent source, Transferable data, int action) {
            super.exportDone(source, data, action);
            // Clean up and remove the LayerItem that was moved
            ((LayerItem) source).setVisible(false);
            ((LayerItem) source).getParent().remove((LayerItem) source);
        }

    }
}

Here is the class for the JPanel:

public class LayerContainer extends JPanel {

    public LayerContainer() {
        this.setTransferHandler(new ValueImportTransferHandler());
        this.setLayout(new GridBagLayout()); // Optional layout
        this.setBorder(new CompoundBorder(new LineBorder(Color.DARK_GRAY), new EmptyBorder(20, 20, 20, 20))); // Optional border
    }

    protected static class ValueImportTransferHandler extends TransferHandler {

        public static final DataFlavor SUPPORTED_DATE_FLAVOR = DataFlavor.stringFlavor;

        public ValueImportTransferHandler() {
        }

        @Override
        public boolean canImport(TransferHandler.TransferSupport support) {
            return support.isDataFlavorSupported(SUPPORTED_DATE_FLAVOR);
        }

        @Override
        public boolean importData(TransferHandler.TransferSupport support) {
            boolean accept = false;
            if (canImport(support)) {
                try {
                    Transferable t = support.getTransferable();
                    Object value = t.getTransferData(SUPPORTED_DATE_FLAVOR);
                    if (value instanceof String) { // Ensure no errors
                        // TODO: here you can create your own handler
                        // ie: ((LayerContainer) component).getHandler()....
                        Component component = support.getComponent();
                        LayerItem j = new LayerItem((String) value);
                        ((LayerContainer) component).add(j); // Add a new drag JLabel
                        accept = true;
                    }
                } catch (Exception exp) {
                    exp.printStackTrace();
                }
            }
            return accept;
        }
    }

}

Here is an example of how you could use this (drag from one JPanel to another and back again):

    JPanel left_panel = new LayerContainer();
    panel_1.setBounds(28, 47, 129, 97);
    add(panel_1);

    LayerContainer right_panel = new LayerContainer();
    layerContainer.setBounds(203, 47, 129, 97);
    add(layerContainer);

    JLabel lblToDrag = new LayerItem("Drag Me");
    GridBagConstraints gbc_lblToDrag = new GridBagConstraints();
    gbc_lblDragMe.gridx = 0;
    gbc_lblDragMe.gridy = 0;
    panel_right.add(lblToDrag, gbc_lblToDrag);

For future use, I'll create a onTransfer() method and create my own LayerContainerHandler() which overrites a run() method so each time a Label is moved to different Containers, it execute seperate actions.

Jaquarh
  • 6,493
  • 7
  • 34
  • 86