Search code examples
javaswingawtactionlistenerinfinite-loop

Checking options in empty Infinite loop vs dosomething infite loop


public static void main(String... s) {
        StartUp obj = new StartUp();
          
        while(true) {
            //System.out.println("Option - " + option);
            if(option == 1) {
                option = 0;
                obj.setVisible(false);
                obj.dispose();
                new Test();
                break;
            }else if(option == 2) {
                option = 0;
                obj.setVisible(false);
                obj.dispose();
                new PWorld.Splash().load();
                break;
            }
        }
    }
    

I need to put System.out.println("Option - " + option); inside the while loop for it to work otherwise the programe freezes after running StartUp obj = new StartUp();

option is a static int inside StartUp class and is changed by a Actionlistener the value in option is changed by ActionListener but while loop doesn't seems to work.

But if I put System.out.println("Option - " + option); inside while loop, it works. WHY!

I'm using this while loop because new PWorld.Splash().load(); has Thread.sleep(), and as in this answere new JFrame will not be drawn if called from ActionListener(in UI Thread)which has Thread.

Thank you


Solution

  • Your issues are:

    • You're calling a "tight" loop, one that hogs the CPU and blocks other code from running. The System.out.println(...) statement adds code that slows this loop, releasing the CPU from the jaws of the tight loop, allowing other threads to run, and this is the genesis of your question.
    • Having said that, again, your coding approach is not good, in that you're using a while (true) loop in place of responding to an event, which is how Swing GUI's should be coded.
    • You state that the reason for this is that one bit of code in the while loop calls a Thread.sleep and that this code, if called on the Swing event thread, such as within an ActionListener, will block the event thread, freezing your GUI -- all true.
    • But your solution is wrong. The correct solution is not to call this in a while (true) loop in the main method, but rather to either call the Thread.sleep from a background thread, such as within the doInBackground() method of a SwingWorker (link is to tutorial), or better still, to use a Swing Timer (again, link is to tutorial) in place of the Thread.sleep. This will allow your code to pause some code without blocking the Swing event thread.
    • Another option, if you need to show a dialog (sub) window is to use a modal JDialog to show a window while blocking interaction with the main GUI window, until the dialog window is no longer visible.

    For a more detailed and comprehensive solution, again, please consider creating and posting your Minimal, Reproducible Example program with your question.

    For example, here is my Minimal, Reproducible Example:

    import java.awt.Dialog.ModalityType;
    import java.awt.Dimension;
    import java.awt.Color;
    import java.awt.GridBagLayout;
    import java.awt.GridLayout;
    import java.awt.Window;
    import javax.swing.*;
    
    public class MinReproExample {
        public static void main(String[] args) {
            SwingUtilities.invokeLater(() -> {
                Startup startup = new Startup();
                startup.showStartUp();
    
                Option option = startup.getOption();
                if (option == Option.TEST) {
                    JOptionPane.showMessageDialog(null, "Test selected", "Selection", JOptionPane.DEFAULT_OPTION);
                } else if (option == Option.PWORLD) {
                    PWorld pworld = new PWorld();
                    pworld.showSplash();
                }   
            });
        }
    }
    
    class Startup {
        private JDialog startupDialog;
        private Option option = null;
        
        public Startup() {
            ButtonGroup buttonGroup = new ButtonGroup();
            JPanel optionsPanel = new JPanel(new GridLayout(1, 0, 10, 10));
            optionsPanel.setBorder(BorderFactory.createTitledBorder("Options"));
            for (final Option op : Option.values()) {
                JRadioButton rBtn = new JRadioButton(op.getText());
                rBtn.setActionCommand(op.getText());
                optionsPanel.add(rBtn);
                buttonGroup.add(rBtn);
                rBtn.addActionListener(e -> {
                    option = op;
                    Window window = SwingUtilities.getWindowAncestor(optionsPanel);
                    window.dispose();
                });
            }
            
            startupDialog = new JDialog(null, "Select Option", ModalityType.APPLICATION_MODAL);
            startupDialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
            startupDialog.add(optionsPanel);
            startupDialog.pack();
            startupDialog.setLocationRelativeTo(null);
        }
        
        public void showStartUp() {
            if (startupDialog != null) {
                startupDialog.setVisible(true);
            }
        }
        
        public Option getOption() {
            return option;
        }
    }
    
    class PWorld {
        private static final Color ROBINS_EGG_BLUE = new Color(0, 204, 204);
        private JDialog pworldSplashDialog;
        private JFrame mainPWorldFrame;
    
        public PWorld() {
            JLabel splashLabel = new JLabel("Splash Window", SwingConstants.CENTER);
            JPanel splashPanel = new JPanel(new GridBagLayout());
            splashPanel.add(splashLabel);
            splashPanel.setBackground(Color.PINK);
            splashPanel.setPreferredSize(new Dimension(300, 250));
    
            pworldSplashDialog = new JDialog(null, "Splash", ModalityType.MODELESS);
            pworldSplashDialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
            pworldSplashDialog.add(splashPanel);
            pworldSplashDialog.pack();
            pworldSplashDialog.setLocationRelativeTo(null);
    
            JLabel mainLabel = new JLabel("Main GUI Window", SwingConstants.CENTER);
            JPanel mainPanel = new JPanel(new GridBagLayout());
            mainPanel.add(mainLabel);
            mainPanel.setBackground(ROBINS_EGG_BLUE);
            mainPanel.setPreferredSize(new Dimension(500, 350));
    
            mainPWorldFrame = new JFrame("Main PWorld GUI");
            mainPWorldFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            mainPWorldFrame.add(mainPanel);
            mainPWorldFrame.pack();
            mainPWorldFrame.setLocationRelativeTo(null);
    
        }
    
        public void showSplash() {
            int timerDelay = 2000; // two second delay
            Timer timer = new Timer(timerDelay, e -> {
                if (pworldSplashDialog != null && pworldSplashDialog.isVisible()) {
                    pworldSplashDialog.dispose();
                    showMainPWorldFrame();
                }
            });
            timer.setRepeats(false);
            timer.start();
    
            pworldSplashDialog.setVisible(true);
        }
    
        private void showMainPWorldFrame() {
            mainPWorldFrame.setVisible(true);
        }
    }
    
    // options to choose from
    enum Option {
        TEST("Test"), PWORLD("PWorld");
        private String text;
    
        private Option(String text) {
            this.text = text;
        }
    
        public String getText() {
            return text;
        }
    }