简体   繁体   中英

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

Above is Minimal, Reproducible Example of my problem.
When Progress JFrame is called from ActionListner, the JFrame doesn't appear properly. I get a black JFrame and after a sec I get final JFrame with full progressbar. But if I call new Progress() directly, it works properly(ie seeing progressbar filling up).
I found that creating new Thread in UI thread is unable to draw Frame. And I should use Swing.Timer .
I don't know how to do it with Swing.Timer . Any other approach is appreciated.

obj.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

There's the immediate problem, but there are so many more. Change it to the following to ensure the JRE does not exit once it is disposed:

obj.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

As to some of the other problems:

  • See The Use of Multiple JFrames, Good/Bad Practice? In this case I'd recommend one of two approaches, after refactoring each GUI into a panel:
    1. Display both panels in one frame using CardLayout as shown in this answer .
    2. Use a JDialog instead of the 2nd frame.
  • Always start and update the GUI on the Event Dispatch Thread. Not doing so causes unpredictable differences.
  • Don't ignore exceptions. They inform us exactly what went wrong, Unless logging is implemented, at least call Throwable.printStackTrace()

Problem #1

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

Call setVisible last, after you've established the UI. If you need to update the UI after it's visible, you should call invalidate and repaint to trigger a new layout and paint pass

Problem #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) {}

Ok, this is actually tw problems.

First, Swing is NOT thread safe and you should not update the UI from outside the context of the Event Dispatching Thread. You should, as you said, either use a Swing Timer or probably more suitably, a SwingWorker

Secondly, t1.join is blocking the current thread. Because this constructor was called from the ActionListener , this means you're in the context of the Event Dispatching Thread ie, the thread used to update the UI with, so, nothing will change until the thread is completed

For example:

Other problems...

I'd also discuss things about using multiple frames, setBounds of things like pack , setLocationRelativeTo and using other things like borders or layout constraints to increase the padding, but there are plenty of other examples

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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