0
public class Start extends JFrame{
public static void main(String...s){
    Start obj = new Start();
    obj.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    obj.setBounds(100,100,300,300);
    JPanel main = new JPanel();
    obj.add(main);
    JButton btn = new JButton("Login");
    main.add(btn);
    btn.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            obj.setVisible(false);
            obj.dispose();
            new Progress();
        }
    });
    obj.setVisible(true);
}
}

class Progress extends JFrame{
int pro = 0;
Progress(){
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setVisible(true);
    setBounds(100,100,300,300);
    JPanel main = new JPanel();
    add(main);
    main.add(new JLabel("ejfbasj")); 
    JProgressBar progressBar = new JProgressBar(0,100);
    main.add(progressBar);
    Thread t1 = new Thread() {
        public void run() {
            while(pro<=100) {
                /*
                 * Do something - set progressbar value
                 * */
                try {
                    sleep(10);
                } catch (InterruptedException e) {}
                progressBar.setValue(pro);
                pro++;
            }
        }
    };
    t1.start();
    //Do something - gives progress values
    try {
        t1.join();
    } catch (InterruptedException e) {}
}
}

以上是我的问题的最小,可重现的示例。
从 ActionListner 调用 Progress JFrame 时,JFrame 无法正确显示。我得到一个黑色的 JFrame,一秒钟后我得到了带有完整进度条的最终 JFrame。但如果我new Progress()直接打电话,它可以正常工作(即看到进度条填满)。
我发现在 UI 线程中创建新线程无法绘制 Frame。我应该使用Swing.Timer.
我不知道该怎么做Swing.Timer。任何其他方法都值得赞赏。

4

2 回答 2

2
obj.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

有直接的问题,但还有更多。将其更改为以下内容以确保 JRE 在处理后不会退出:

obj.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

至于其他一些问题:

  • 请参阅使用多个 JFrame,好/坏做法?在这种情况下,在将每个 GUI 重构为面板之后,我会推荐以下两种方法之一:
    1. 使用此答案CardLayout中所示的方式在一个框架中显示两个面板。
    2. 使用 aJDialog而不是第二帧。
  • 始终在事件调度线程上启动和更新 GUI。不这样做会导致不可预测的差异。
  • 不要忽视异常!他们准确地告诉我们出了什么问题。除非实现了日志记录,否则至少调用Throwable.printStackTrace()
于 2020-08-30T01:54:38.590 回答
1

问题 #1

Progress(){
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setVisible(true);

setVisible建立 UI 后,最后调用。如果您需要在 UI 可见后更新它,您应该调用invalidaterepaint触发新的布局和绘制通道

问题 #2

Thread t1 = new Thread() {
    public void run() {
        while(pro<=100) {
            /*
             * Do something - set progressbar value
             * */
            try {
                sleep(10);
            } catch (InterruptedException e) {}
            progressBar.setValue(pro);
            pro++;
        }
    }
};
t1.start();
//Do something - gives progress values
try {
    t1.join();
} catch (InterruptedException e) {}

好的,这实际上是两个问题。

首先,Swing 不是线程安全的,您不应该从 Event Dispatching Thread 的上下文之外更新 UI。正如您所说,您应该使用 SwingTimer或更合适的SwingWorker

其次,t1.join是阻塞当前线程。因为此构造函数是从 调用的ActionListener,这意味着您处于事件调度线程的上下文中,即用于更新 UI 的线程,因此,在线程完成之前不会发生任何变化

例如:

其他问题...

我还将讨论有关使用多个框架setBounds的事情,例如packsetLocationRelativeTo以及使用边框或布局约束等其他内容来增加填充,但还有很多其他示例

于 2020-08-29T22:05:58.567 回答