Search code examples
javaswingjoptionpane

Custom JOptionPane / How to wait for a button in a frame to be clicked before returning a value to a method


I am trying to create a method which opens up a JFrame with some text and 4 JButtons. I need it to operate just like the methods in the JOptionPane class so that i can do things like

int i = JOptionPane.showConfirmDialog(...);

I want to be able to call the method and wait for one of the buttons to be clicked before returning a value.

This is what I have tried so far but obviously there are a couple of errors. Anybody know what i need to do to make this work and how to get around the errors. Here is the methood

private static String displaySetStatus(String text){
        JButton jbtWin = new JButton("Win");
        JButton jbtLose = new JButton("Lose");
        JButton jbtCancelBet = new JButton("Cancel Bet");
        JButton jbtSkip = new JButton("Skip");
        JFrame f = new JFrame("Set Status");

        f.add(new JLabel(text));
        JPanel jpSouth = new JPanel();
        jpSouth.add(jbtWin);
        jpSouth.add(jbtLose);
        jpSouth.add(jbtCancelBet);
        jpSouth.add(jbtSkip);
        f.add(jpSouth, "South");

        f.setSize(200, 150);
        f.setLocationRelativeTo(null);
        f.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
        f.setVisible(true);

        String status = "Empty";

        ActionListener buttonListener = new SetStatusListener();
        jbtWin.addActionListener(buttonListener);
        jbtLose.addActionListener(buttonListener);
        jbtCancelBet.addActionListener(buttonListener);
        jbtSkip.addActionListener(buttonListener);


        class SetStatusListener implements ActionListener{
            @Override
            public void actionPerformed(ActionEvent e) {
                status = ((JButton)e.getSource()).getText();
            } 
        }

        while(status.equals("Empty")){
            //do nothing - wait until button is clicked
        }

        f.setVisible(false);
        return status;
    }

Solution

  • If you want JOptionPane functionality, which is in fact that of a modal dialog window, why not use a JOptionPane for this? Or if that won't work, use a modal JDialog window and not a JFrame. Your while (true) block is going to totally mess up your program, and modality is what you in fact want.

    For example:

    import java.awt.Component;
    import java.awt.Dimension;
    import java.awt.GridBagLayout;
    import java.awt.event.ActionEvent;
    
    import javax.swing.AbstractAction;
    import javax.swing.Icon;
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JOptionPane;
    import javax.swing.JPanel;
    import javax.swing.JTextField;
    import javax.swing.SwingUtilities;
    
    @SuppressWarnings("serial")
    public class Foo1 extends JPanel {
        private JTextField textField = new JTextField(10);
        private JButton getStatusBtn = new JButton(new GetStatusAction("Get Status"));
    
        public Foo1() {
            textField.setFocusable(false);
            add(new JLabel("Status:"));
            add(textField);
            add(getStatusBtn);
        }
    
        private class GetStatusAction extends AbstractAction {
            public GetStatusAction(String name) {
                super(name);
                int mnemonic = name.charAt(0);
                putValue(MNEMONIC_KEY, mnemonic);
            }
    
            @Override
            public void actionPerformed(ActionEvent e) {
                Component parentComponent = Foo1.this;
    
                // this panel can hold any gui components that you desire
                // here I simply give it a centered JLabel that displays some text
                JPanel message = new JPanel(new GridBagLayout());
                message.setPreferredSize(new Dimension(200, 100));
                message.add(new JLabel("Some Text"));
                String title = "Get Status";
                int optionType = JOptionPane.OK_CANCEL_OPTION;
                int messageType = JOptionPane.PLAIN_MESSAGE;
                Icon icon = null;
                String[] options = { "Win", "Lose" };
                int initialValue = 0;
    
                // create and show our JOptionPane, and get the information from it
                int selection = JOptionPane.showOptionDialog(parentComponent,
                        message, title, optionType, messageType, icon, options,
                        initialValue);
    
                // if the selection chosen was valid (win or lose pushed)
                if (selection >= 0) {
                    // get the selection and use it
                    textField.setText(options[selection]);
                }
            }
        }
    
        private static void createAndShowGui() {
            Foo1 mainPanel = new Foo1();
    
            JFrame frame = new JFrame("Foo1");
            frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
            frame.getContentPane().add(mainPanel);
            frame.pack();
            frame.setLocationByPlatform(true);
            frame.setVisible(true);
        }
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    createAndShowGui();
                }
            });
        }
    }