点击JButton打开预配置组件的JFrame时空白且无法关闭的问题求助
Java Swing JFrame空白且无法关闭问题排查与解决
问题描述
点击某JFrame中的JButton打开预定义组件的JFrame时,新窗口完全空白且无法关闭。相关场景说明:
- 目标JFrame:预期打开的包含时间显示组件的窗口
- 按钮触发代码:负责打开新窗口的按钮点击事件逻辑
- 异常JFrame:点击后出现的空白、无响应关闭操作的窗口
相关代码
DisplayTimeDate.java
import java.awt.Color; import java.awt.FlowLayout; import java.awt.Font; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.text.SimpleDateFormat; import java.util.Calendar; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; public class DisplayTimeDate extends JFrame { Calendar calendar; SimpleDateFormat timeFormat; SimpleDateFormat dayFormat; SimpleDateFormat dateFormat; JLabel timeLabel; JLabel dayLabel; JLabel dateLabel; String time; String day; String date; private JButton btnNewButton; public DisplayTimeDate() { this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setTitle("My Clock Program"); this.setSize(350, 200); this.setResizable(false); timeFormat = new SimpleDateFormat("hh:mm:ss a"); dayFormat = new SimpleDateFormat("EEEE"); dateFormat = new SimpleDateFormat("MMMMM dd, yyyy"); timeLabel = new JLabel(); timeLabel.setFont(new Font("Verdana", Font.PLAIN, 50)); timeLabel.setForeground(new Color(0x00FF00)); timeLabel.setBackground(Color.black); timeLabel.setOpaque(true); dayLabel = new JLabel(); dayLabel.setFont(new Font("Ink Free", Font.PLAIN, 35)); dateLabel = new JLabel(); dateLabel.setFont(new Font("Ink Free", Font.PLAIN, 25)); getContentPane().setLayout(new FlowLayout(FlowLayout.CENTER, 5, 5)); btnNewButton = new JButton(""); btnNewButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { dispose(); testTime_take_2 newFrame = new testTime_take_2(); newFrame.setVisible(true); } }); getContentPane().add(btnNewButton); getContentPane().add(timeLabel); getContentPane().add(dayLabel); getContentPane().add(dateLabel); this.setVisible(true); setTime(); } public void setTime() { while (true) { time = timeFormat.format(Calendar.getInstance().getTime()); timeLabel.setText(time); day = dayFormat.format(Calendar.getInstance().getTime()); dayLabel.setText(day); date = dateFormat.format(Calendar.getInstance().getTime()); dateLabel.setText(date); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } public static void main(String[] args) { new DisplayTimeDate(); } }
testTime_take_2.java(目标JFrame类)
import java.text.SimpleDateFormat; import java.util.Calendar; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.border.EmptyBorder; import javax.swing.SwingConstants; public class testTime_take_2 extends JFrame { private static JFrame frame; private JPanel contentPane; SimpleDateFormat timeFormat; SimpleDateFormat dayFormat; SimpleDateFormat dateFormat; JLabel timeLabel; JLabel dayLabel; String day; String time; String date; private JLabel dateLabel; public static void main(String[] args) { new testTime_take_2(); } public testTime_take_2() { frame = new JFrame(); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setBounds(100, 100, 450, 300); contentPane = new JPanel(); contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); setContentPane(contentPane); timeFormat = new SimpleDateFormat("hh:mm:ss a"); dayFormat = new SimpleDateFormat("EEEE"); dateFormat = new SimpleDateFormat("dd-MMMMM-yyyy"); contentPane.setLayout(null); timeLabel = new JLabel(); timeLabel.setHorizontalAlignment(SwingConstants.CENTER); timeLabel.setBounds(151, 45, 112, 14); timeLabel.setText(time); dayLabel = new JLabel(); dayLabel.setHorizontalAlignment(SwingConstants.CENTER); dayLabel.setBounds(151, 100, 112, 14); getContentPane().add(timeLabel); getContentPane().add(dayLabel); dateLabel = new JLabel(); dateLabel.setHorizontalAlignment(SwingConstants.CENTER); dateLabel.setBounds(151, 151, 112, 14); contentPane.add(dateLabel); setVisible(true); setTime(); } public void setTime() { while(true) { time = timeFormat.format(Calendar.getInstance().getTime()); timeLabel.setText(time); day = dayFormat.format(Calendar.getInstance().getTime()); dayLabel.setText(day); date = dateFormat.format(Calendar.getInstance().getTime()); dateLabel.setText(date); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } public static void main(String[] args) { } }
问题根源
- EDT线程阻塞:两个窗口的
setTime()方法都在Swing的**事件调度线程(EDT)**中执行无限循环+Thread.sleep(1000),直接卡死UI渲染和事件响应,导致新窗口无法绘制组件、关闭按钮无反应。 - 冗余JFrame实例:
testTime_take_2类本身继承JFrame,但构造函数又创建静态frame实例,造成窗口实例混乱。 - 线程不安全的UI更新:直接在非EDT线程修改Swing组件,违反Swing单线程模型规范。
修复方案
修复后的DisplayTimeDate.java
import java.awt.Color; import java.awt.FlowLayout; import java.awt.Font; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.text.SimpleDateFormat; import java.util.Calendar; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.SwingUtilities; public class DisplayTimeDate extends JFrame { SimpleDateFormat timeFormat; SimpleDateFormat dayFormat; SimpleDateFormat dateFormat; JLabel timeLabel; JLabel dayLabel; JLabel dateLabel; private JButton btnNewButton; private Thread timeThread; public DisplayTimeDate() { this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setTitle("My Clock Program"); this.setSize(350, 200); this.setResizable(false); timeFormat = new SimpleDateFormat("hh:mm:ss a"); dayFormat = new SimpleDateFormat("EEEE"); dateFormat = new SimpleDateFormat("MMMMM dd, yyyy"); timeLabel = new JLabel(); timeLabel.setFont(new Font("Verdana", Font.PLAIN, 50)); timeLabel.setForeground(new Color(0x00FF00)); timeLabel.setBackground(Color.black); timeLabel.setOpaque(true); dayLabel = new JLabel(); dayLabel.setFont(new Font("Ink Free", Font.PLAIN, 35)); dateLabel = new JLabel(); dateLabel.setFont(new Font("Ink Free", Font.PLAIN, 25)); getContentPane().setLayout(new FlowLayout(FlowLayout.CENTER, 5, 5)); btnNewButton = new JButton("Open New Frame"); btnNewButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { dispose(); if (timeThread != null) { timeThread.interrupt(); } new testTime_take_2(); } }); getContentPane().add(btnNewButton); getContentPane().add(timeLabel); getContentPane().add(dayLabel); getContentPane().add(dateLabel); this.setVisible(true); startTimer(); } private void startTimer() { timeThread = new Thread(() -> { while (!Thread.currentThread().isInterrupted()) { String time = timeFormat.format(Calendar.getInstance().getTime()); String day = dayFormat.format(Calendar.getInstance().getTime()); String date = dateFormat.format(Calendar.getInstance().getTime()); SwingUtilities.invokeLater(() -> { timeLabel.setText(time); dayLabel.setText(day); dateLabel.setText(date); }); try { Thread.sleep(1000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } }); timeThread.start(); } public static void main(String[] args) { SwingUtilities.invokeLater(DisplayTimeDate::new); } }
修复后的testTime_take_2.java
import java.text.SimpleDateFormat; import java.util.Calendar; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.SwingConstants; import javax.swing.SwingUtilities; import javax.swing.border.EmptyBorder; public class testTime_take_2 extends JFrame { private JPanel contentPane; SimpleDateFormat timeFormat; SimpleDateFormat dayFormat; SimpleDateFormat dateFormat; JLabel timeLabel; JLabel dayLabel; JLabel dateLabel; private Thread timeThread; public testTime_take_2() { setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setBounds(100, 100, 450, 300); contentPane = new JPanel(); contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); setContentPane(contentPane); contentPane.setLayout(null); timeFormat = new SimpleDateFormat("hh:mm:ss a"); dayFormat = new SimpleDateFormat("EEEE"); dateFormat = new SimpleDateFormat("dd-MMMMM-yyyy"); timeLabel = new JLabel(); timeLabel.setHorizontalAlignment(SwingConstants.CENTER); timeLabel.setBounds(151, 45, 112, 14); contentPane.add(timeLabel); dayLabel = new JLabel(); dayLabel.setHorizontalAlignment(SwingConstants.CENTER); dayLabel.setBounds(151, 100, 112, 14); contentPane.add(dayLabel); dateLabel = new JLabel(); dateLabel.setHorizontalAlignment(SwingConstants.CENTER); dateLabel.setBounds(151, 151, 112, 14); contentPane.add(dateLabel); this.setVisible(true); startTimer(); } private void startTimer() { timeThread = new Thread(() -> { while (!Thread.currentThread().isInterrupted()) { String time = timeFormat.format(Calendar.getInstance().getTime()); String day = dayFormat.format(Calendar.getInstance().getTime()); String date = dateFormat.format(Calendar.getInstance().getTime()); SwingUtilities.invokeLater(() -> { timeLabel.setText(time); dayLabel.setText(day); dateLabel.setText(date); }); try { Thread.sleep(1000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } }); timeThread.start(); } @Override public void dispose() { if (timeThread != null) { timeThread.interrupt(); } super.dispose(); } public static void main(String[] args) { SwingUtilities.invokeLater(testTime_take_2::new); } }
关键修复点总结
- 所有Swing组件的创建和更新必须通过
SwingUtilities.invokeLater()在EDT中执行,符合单线程模型规范。 - 耗时的循环、睡眠操作必须放到独立线程中,绝对不能阻塞EDT。
- 移除冗余的JFrame实例,继承JFrame后直接使用当前实例即可。
- 正确处理线程中断,窗口关闭时终止后台线程,避免资源泄漏。
内容的提问来源于stack exchange,提问作者Quan Tran
相关产品推荐
相关产品推荐

