0

I have an application where I allow strings to be dragged and dropped on to one of the components. This works fine.

Now I want to be able to add customization options to this operation. My first attempt is to construct and show a JPopupMenu after the drop action has been accepted. This does not seem to work as the popup menu is not being displayed, it is like the show method is being ignored.

Is there any workaround for this behaviour, or will I have to use something heavier like a JOptionPane?

Here is my sample code:

import javax.swing.*;
import java.awt.*;
import java.awt.datatransfer.DataFlavor;
import java.awt.dnd.DropTarget;
import java.awt.dnd.DropTargetAdapter;
import java.awt.dnd.DropTargetDropEvent;

import static java.awt.dnd.DnDConstants.ACTION_COPY;

public class DNDTest {

    DNDTest() {
        JFrame f = new JFrame("Test dnd");
        Container c = f.getContentPane();
        final JPanel jp = new JPanel(new BorderLayout());
        jp.setBackground(Color.RED);
        jp.setToolTipText("Drop a string here");
        jp.setPreferredSize(new Dimension(200,200));
        c.add(jp);

        DropTarget dt = new DropTarget(jp, ACTION_COPY, new DropTargetAdapter() {
            @Override
            public void drop(DropTargetDropEvent dtde) {
                if (dtde.isDataFlavorSupported(DataFlavor.stringFlavor)) {
                    try {
                        dtde.acceptDrop(ACTION_COPY);
                        String trns = (String) dtde.getTransferable().getTransferData(DataFlavor.stringFlavor);
                        System.err.println("Dropped string "+trns);
                        Point loc = dtde.getLocation();

                        // Show a popup after the drop operation
                        JPopupMenu jpm2 = new JPopupMenu("Popup menu");
                        JMenuItem jmi2 = new JMenuItem("Popup option 1");
                        jpm2.add(jmi2);
                        System.err.println("About to show popup after drop at "+loc.getX()+","+loc.getY());
                        jpm2.show(jp, (int)loc.getX(), (int)loc.getY());
                    } catch (Exception ex) {
                        ex.printStackTrace();
                    }
                    return;
                }
                dtde.rejectDrop();
            }
        }, true);

        f.pack();
        f.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(DNDTest::new);
    }
}
1

2 Answers 2

2

It looks, that the current mouse event ("drop event") causes the menu to direct disappear. You simply need to show your menu in "invokeLater" method.

import static java.awt.dnd.DnDConstants.ACTION_COPY;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.datatransfer.DataFlavor;
import java.awt.dnd.DropTarget;
import java.awt.dnd.DropTargetAdapter;
import java.awt.dnd.DropTargetDropEvent;

import javax.swing.JFrame;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.SwingUtilities;

public class DNDTest {

    DNDTest() {
        JFrame f = new JFrame("Test dnd");
        Container c = f.getContentPane();
        final JPanel jp = new JPanel(new BorderLayout());
        jp.setBackground(Color.RED);
        jp.setToolTipText("Drop a string here");
        jp.setPreferredSize(new Dimension(200, 200));
        c.add(jp);

        DropTarget dt = new DropTarget(jp, ACTION_COPY, new DropTargetAdapter() {
            @Override
            public void drop(DropTargetDropEvent dtde) {
                if (dtde.isDataFlavorSupported(DataFlavor.stringFlavor)) {
                    try {
                        dtde.acceptDrop(ACTION_COPY);
                        String trns = (String) dtde.getTransferable().getTransferData(DataFlavor.stringFlavor);
                        System.err.println("Dropped string " + trns);
                        Point loc = dtde.getLocation();

                        // Show a popup after the drop operation
                        JPopupMenu jpm2 = new JPopupMenu();
                        JMenuItem jmi2 = new JMenuItem("Popup option 1");
                        jpm2.add(jmi2);
                        System.err.println("About to show popup after drop at " + loc.getX() + "," + loc.getY());
                        SwingUtilities.invokeLater(() -> jpm2.show(jp, (int) loc.getX(), (int) loc.getY()));
                    } catch (Exception ex) {
                        ex.printStackTrace();
                    }
                    return;
                }
                dtde.rejectDrop();
            }
        }, true);

        f.pack();
        f.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(DNDTest::new);
    }
}
0
-1

Your code seems to work fine if you add a drag source for the String:

// ....
final JPanel jp = new JPanel(new BorderLayout());
JTextField jtf = new JTextField("Drag me");
jtf.setDragEnabled(true);
jp.add(jtf, BorderLayout.PAGE_START);
jp.setBackground(Color.RED);
jp.setToolTipText("Drop a string here");
// ....
1
  • 1
    That's not it. The drag source does not have to be within the same app. It can come from a different app altogether (such as dragging text out of a text editor).
    – opeongo
    Commented Jun 28 at 18:13

Not the answer you're looking for? Browse other questions tagged or ask your own question.