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

点击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) {
    }
}

问题根源

  1. EDT线程阻塞:两个窗口的setTime()方法都在Swing的**事件调度线程(EDT)**中执行无限循环+Thread.sleep(1000),直接卡死UI渲染和事件响应,导致新窗口无法绘制组件、关闭按钮无反应。
  2. 冗余JFrame实例:testTime_take_2类本身继承JFrame,但构造函数又创建静态frame实例,造成窗口实例混乱。
  3. 线程不安全的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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 14:21:01