繁体   English   中英

JFrame 从 ActionListener 调用时未正确显示

[英]JFrame not showing up properly when called from ActionListener

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线程中新建Thread是无法绘制Frame的。 我应该使用Swing.Timer
我不知道如何使用Swing.Timer来做到这一点。 任何其他方法表示赞赏。

obj.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

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

obj.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

至于其他一些问题:

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

问题#1

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

在建立 UI 之后,最后调用setVisible 如果您需要在 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 不是线程安全的,您不应该从事件调度线程的上下文之外更新 UI。 正如您所说,您应该使用 Swing Timer或者可能更合适地使用SwingWorker

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

例如:

其他问题...

我还将讨论有关使用多个框架、 setBounds之类的东西packsetLocationRelativeTo以及使用其他东西(例如边框或布局约束)来增加填充的事情,但是还有很多其他示例

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM