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

线程中JFrame无法销毁及名称异常问题求助

问题分析与修复方案

核心问题原因

你遇到的frame名称不一致、窗口无法销毁的问题,根源在于错误地创建了多个RegisterExercise实例:

  • 在RegisterExercise的initializeFrame方法中,你通过new RegisterExercise().mainPanel创建了一个全新的RegisterExercise对象,这个新对象会自动生成自己的JFrame(即日志中的frame1)。
  • 你把原本的frame0的内容面板替换成了新实例的mainPanel,导致用户实际点击的btnCancel属于这个新实例,它的监听器绑定的是新实例的frame1,而显示的窗口却是最初的frame0。调用frame.dispose()只会销毁看不见的frame1,frame0依然存在。
  • 即使frame被final修饰,这里的问题是你混淆了两个不同实例的frame,它们完全是两个独立对象。

另外,Menu类的run方法中也存在同样的错误:通过new Menu().mainPanel创建了新的Menu实例,导致当前实例的监听器无法生效。

修复后的代码

修复RegisterExercise类

public class RegisterExercise extends Thread {

    private final JFrame frame;
    private JButton btnSave;
    private JPanel mainPanel;
    private JButton btnCancel;
    private JTextField txtName;
    private JTextField txtEasyName;
    private JTextField txtDescription;
    private JTextField txtMachineName;
    private JLabel lblName;
    private JLabel lblEasyName;
    private JLabel lblDescription;
    private JLabel lblMachineName;

    public RegisterExercise() {
        frame = new JFrame("Register an exercise");
        // 给当前实例的btnCancel绑定监听器
        btnCancel.addActionListener(e -> {
            System.out.println("Frame:" + frame.getName());
            frame.dispose();
        });
    }

    @Override
    public void run() {
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException |
                 UnsupportedLookAndFeelException e) {
            throw new RuntimeException(e);
        }
        initializeFrame(frame);
        super.run();
    }

    private void initializeFrame(JFrame frame) {
        // 使用当前实例的mainPanel,避免创建新的RegisterExercise对象
        frame.setContentPane(this.mainPanel);
        frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
        frame.pack();
        frame.setVisible(true);
        System.out.println("This is frame:" + frame.getName());
    }
}

修复Menu类

public class Menu extends Thread {

    private JButton btnExit;
    private JPanel mainPanel;
    private JButton btnRegisterExercise;
    private JTable menuTable;
    private JLabel lblVersion;

    private RegisterExercise registerExercise;

    public Menu() {
        btnExit.addActionListener(e -> {
            int answer = JOptionPane.showConfirmDialog(null, "Do you want to leave?", "Leaving", JOptionPane.YES_NO_OPTION);
            if (answer == JOptionPane.YES_OPTION) {
                System.exit(0);
            }
        });

        btnRegisterExercise.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                // 允许窗口销毁后重新打开
                if (registerExercise == null || !registerExercise.frame.isDisplayable()) {
                    registerExercise = new RegisterExercise();
                    registerExercise.start();
                }
            }
        });
    }

    @Override
    public void run() {
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException |
                 UnsupportedLookAndFeelException e) {
            throw new RuntimeException(e);
        }
        JFrame frame = new JFrame("My Move Gym");
        // 使用当前实例的mainPanel,避免创建新的Menu对象
        frame.setContentPane(this.mainPanel);
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.pack();
        frame.setVisible(true);
        super.run();
    }
}

额外说明

  • 修复后,点击btnCancel时会直接操作显示的frame0,调用dispose()可以正常销毁窗口,无需使用System.exit(0)。
  • Menu类中添加了窗口状态判断,允许用户在窗口销毁后再次点击按钮重新打开注册窗口。
  • (可选优化)Swing组件的创建和更新应该在事件调度线程(EDT)中执行,你可以将窗口初始化代码包装在SwingUtilities.invokeLater()中,避免线程安全问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 17:20:35