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

Java Swing应用添加while循环后卡顿冻结问题求助

解决Swing应用因循环轮询导致的冻结问题

问题根源

Swing采用单线程模型,所有UI事件(按钮点击、组件绘制等)都由事件调度线程(EDT)处理。你在actionPerformed方法里加入的while(framerunning)循环会持续占用EDT,导致EDT无法处理其他UI操作(比如Spinner输入、窗口重绘),直接引发应用卡顿冻结。

正确解决方案

放弃循环轮询的方式,改用JSpinner自带的ChangeListener监听数值变更,实时调整目标窗口大小:

  • 给两个JSpinner添加ChangeListener,值变化时触发回调逻辑
  • 保存生成的目标JFrame实例,方便后续修改其尺寸
  • 移除阻塞EDT的while循环,让EDT能正常处理其他UI事件

修改后的代码

Frame.java

import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class Frame extends JFrame implements ActionListener, ChangeListener {
    SpinnerNumberModel modelheight;
    JSpinner heightinp;
    SpinnerNumberModel modelwidth;
    JSpinner widthinp;
    JButton newframebutton;
    // 保存生成的目标窗口实例
    private JFrame targetFrame;

    Frame(){
        // 初始化Spinner
        modelheight = new SpinnerNumberModel(500, 0, 2000, 1);
        modelwidth = new SpinnerNumberModel(500, 0, 2000, 1);

        heightinp = new JSpinner(modelheight);
        heightinp.setBounds(25,25,250,50);
        // 添加ChangeListener监听值变化
        heightinp.addChangeListener(this);

        widthinp = new JSpinner(modelwidth);
        widthinp.setBounds(25,100,250,50);
        // 添加ChangeListener监听值变化
        widthinp.addChangeListener(this);

        // 初始化按钮
        newframebutton = new JButton("New Frame");
        newframebutton.setBounds(25,175,120,50);
        newframebutton.addActionListener(this);

        // 初始化主窗口面板
        JPanel framepanel = new JPanel();
        framepanel.setPreferredSize(new Dimension(600,600));
        framepanel.setLayout(null);

        framepanel.add(heightinp);
        framepanel.add(widthinp);
        framepanel.add(newframebutton);

        // 主窗口基础设置
        this.add(framepanel);
        this.pack();
        this.setVisible(true);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.getContentPane().setBackground(Color.WHITE);
        this.setLocationRelativeTo(null);
        this.setResizable(false);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        if (e.getSource() == newframebutton){
            // 创建并初始化目标窗口
            targetFrame = new JFrame();
            int height = (int) heightinp.getValue();
            int width = (int) widthinp.getValue();
            targetFrame.setSize(width, height);
            targetFrame.setVisible(true);
            targetFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        }
    }

    @Override
    public void stateChanged(ChangeEvent e) {
        // 当Spinner值变化时,若目标窗口存在且可见则调整尺寸
        if (targetFrame != null && targetFrame.isVisible()){
            int newHeight = (int) heightinp.getValue();
            int newWidth = (int) widthinp.getValue();
            targetFrame.setSize(newWidth, newHeight);
        }
    }
}

Main.java

public class Main {
    public static void main(String[] args) {
        // 确保Swing组件在EDT线程中初始化,符合线程安全规范
        SwingUtilities.invokeLater(Frame::new);
    }
}

关键修改点

  1. 实现ChangeListener接口,用stateChanged方法替代循环轮询逻辑
  2. 给两个JSpinner绑定监听器,实时捕获数值变化
  3. 保存targetFrame实例,方便在值变化时修改窗口尺寸
  4. 主窗口初始化改用SwingUtilities.invokeLater,遵循Swing线程安全要求
  5. 目标窗口关闭方式改为DISPOSE_ON_CLOSE,避免关闭子窗口时退出整个应用

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 08:40:46