You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Java拖拽释放操作中显示JPopupMenu?

问题原因与解决方案

你的问题出在拖拽事件的回调线程不是Swing事件调度线程(EDT),Swing的所有UI操作都必须在EDT中执行,否则会出现组件无法正常渲染的情况——这就是你调用show()后弹窗没显示的原因。不需要改用JOptionPane,只需要把弹窗的创建和显示逻辑放到EDT中执行即可。

修改后的代码

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);
                        final Point loc = dtde.getLocation();

                        // 将弹窗显示逻辑放到EDT中执行
                        SwingUtilities.invokeLater(() -> {
                            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);
    }
}

补充说明

  • Swing的线程规则:所有涉及组件创建、修改、渲染的操作都必须在EDT中完成,非EDT线程直接操作UI会导致不可预测的行为,比如组件不显示、界面卡顿等。
  • SwingUtilities.invokeLater()会把传入的Runnable任务放到EDT的事件队列中,等待EDT空闲时执行,确保UI操作的线程安全性。

内容的提问来源于stack exchange,提问作者opeongo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 19:10:55