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); } }
关键修改点
- 实现
ChangeListener接口,用stateChanged方法替代循环轮询逻辑 - 给两个JSpinner绑定监听器,实时捕获数值变化
- 保存
targetFrame实例,方便在值变化时修改窗口尺寸 - 主窗口初始化改用
SwingUtilities.invokeLater,遵循Swing线程安全要求 - 目标窗口关闭方式改为
DISPOSE_ON_CLOSE,避免关闭子窗口时退出整个应用
内容的提问来源于stack exchange,提问作者MASEH
相关产品推荐
相关产品推荐

