Why does my JFrame open after a for loop?

66 Views Asked by At

I am creating a Java program using Swing and want to open a JFrame, run a for-loop that stores items in a list of Strings, display graphics while that is happening, and only after that is done call another method. The issue is that even though I call frame.setVisible(true); before running the loop, it only displays after the loop is done. I would use a SwingWorker but I need to stop the main thread from running the next method until after the loop is finished. If someone knows a way to use SwingWorker or knows a fix to this, that would be great. Here is the code I am referring to:

//The JPanel in charge of displaying graphics while the loop is running
FrameRenderer renderer = new FrameRenderer(videoFile, this.getWidth(), this.getHeight());
this.add(renderer);

this.setVisible(true);

//Call the method with the for-loop after this.setVisible is called
List<String> frames = renderer.renderFrames();

//I need this to run after the loop is finished
DisplayFrames display = new DisplayFrames(frames, this.getWidth(), this.getHeight(), this);
this.add(display);
1

There are 1 best solutions below

1
MadProgrammer On

SwingWorker

Worker Threads and SwingWorker

enter image description here

import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingWorker;
import javax.swing.border.EmptyBorder;

public final class Main {
    public static void main(String[] args) {
        new Main();
    }

    public Main() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.add(new MainPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class MainPane extends JPanel {
        private JLabel label = new JLabel("...");
        public MainPane() {
            setLayout(new GridBagLayout());
            setBorder(new EmptyBorder(32, 64, 32, 64));
            add(label);

            SwingWorker<Void, String> worker = new SwingWorker<>() {
                @Override
                protected Void doInBackground() throws Exception {
                    for (int index = 0; index < 1000; index++) {
                        publish(Integer.toString(index));
                        // It's important, if you want to allow the UI to
                        // update on a single view, you need to allow time
                        // for this thread to sleep, otherwise, you could
                        // end up in a siutatio where the only update you
                        // get is the last one (with a list of all the 
                        // the values you "published"
                        Thread.sleep(10);
                    }
                    return null;
                }

                @Override
                protected void process(List<String> chunks) {
                    label.setText(chunks.get(chunks.size() - 1));
                }
            };
            worker.addPropertyChangeListener(new PropertyChangeListener() {
                @Override
                public void propertyChange(PropertyChangeEvent evt) {
                    if (worker.getState() == SwingWorker.StateValue.DONE) {
                        label.setText("All done here");
                    }
                }
            });
            worker.execute();
        }
    }
}

Swing Timer

How to Use Swing Timers

enter image description here

import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.border.EmptyBorder;

public final class Main {
    public static void main(String[] args) {
        new Main();
    }

    public Main() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.add(new MainPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class MainPane extends JPanel {
        private JLabel label = new JLabel("...");

        public MainPane() {
            setLayout(new GridBagLayout());
            setBorder(new EmptyBorder(32, 64, 32, 64));
            add(label);

            Timer timer = new Timer(10, new ActionListener() {
                private int value = 0;

                @Override
                public void actionPerformed(ActionEvent e) {
                    if (value >= 1000) {
                        ((Timer)(e.getSource())).stop();
                        label.setText("All done here");
                    }
                    label.setText(Integer.toString(value));
                    value++;
                }
            });
            timer.start();
        }
    }
}