Search code examples
javaswingjbuttonactionlistenerjcombobox

Accessing changes made inside JButton ActionListener outside the ActionListener


I ll explain my code in a bit:

I have a JComboBox with a list of items And when the JButton "Select" is pressed, it registers the last index of the last selected item from JComboBox.

Now I need to access this index inside the main.

Here is my code :

public static final JComboBox c = new JComboBox();

private static final JButton btnNewButton = new JButton("Select");

And the JButton ActionListener is:

btnNewButton.addActionListener(new ActionListener() {

  public void actionPerformed(ActionEvent e)
  {
       ind = c.getSelectedIndex();
        frame.setVisible(false);
    }
  });      

So after the button is pressed, the frame closes

But now when I try to access this ind inside main simply by

public static void main(String[] args) {
System.out.println(ind);}

I get a return value of ind = 0

I understand that this is because it has been initialized to 0 as

static ind = 0 

But then how do I access this index outside the JButton ActionListener?

I need to use this index further in my code.

EDIT

Here's my MCVE

import java.util.ArrayList;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.SpringLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.UIManager;

public class MinimalExProgram
{
private static String[] description = { "One", "Two", "Three"};

static int ind;

public static final JComboBox c = new JComboBox(description);

private static final JButton btnNewButton = new JButton("Select");


public static void main(String[] args) {

JFrame frame = new JFrame();
frame.getContentPane().setForeground(UIManager.getColor("ComboBox.disabledBackground"));
frame.getContentPane().setBackground(UIManager.getColor("EditorPane.disabledBackground"));
SpringLayout springLayout = new SpringLayout();
springLayout.putConstraint(SpringLayout.NORTH, btnNewButton, 5, SpringLayout.NORTH, frame.getContentPane());
springLayout.putConstraint(SpringLayout.EAST, c, -6, SpringLayout.WEST, btnNewButton);
springLayout.putConstraint(SpringLayout.EAST, btnNewButton, -10, SpringLayout.EAST, frame.getContentPane());
springLayout.putConstraint(SpringLayout.WEST, c, 6, SpringLayout.WEST, frame.getContentPane());
springLayout.putConstraint(SpringLayout.NORTH, c, 6, SpringLayout.NORTH, frame.getContentPane());
frame.getContentPane().setLayout(springLayout);
frame.setSize(500, 150);
frame.setLocation(400, 200);
frame.setResizable(false);
c.setBackground(UIManager.getColor("ComboBox.disabledBackground"));


btnNewButton.addActionListener(new ActionListener() {

public void actionPerformed(ActionEvent e)
{
      System.out.print("What I want:");
      ind = c.getSelectedIndex();
      System.out.println(ind);
        frame.setVisible(false);
}
});      

frame.getContentPane().add(c);
btnNewButton.setForeground(UIManager.getColor("ComboBox.buttonDarkShadow"));
btnNewButton.setBackground(UIManager.getColor("EditorPane.disabledBackground    "));

frame.getContentPane().add(btnNewButton);
frame.setVisible(true);
System.out.print("What I get: ");
System.out.println(ind);
}
}

I need to access the ind inside the main as mentioned before Here when I print out the ind I get zero despite whatever choice I make inside the combobox.


Solution

  • OK, I'm going to guess since you've yet to show us enough information to do more than this, but I assume that:

    • You're showing a 2nd window as a dialog off of a main window
    • That this 2nd window is a JFrame and holds your JComboBox and the button
    • That you're making it invisible on button push,
    • That you try to get the information from the combobox, but it's always 0
    • And this may be because you're getting the information before the user has had a chance to interact with the 2nd window.

    If so, the solution is to make the 2nd window a modal dialog window such as a modal JDialog and not a JFrame. This way, the calling code will know exactly when the 2nd window is no longer visible since the calling code's code flow will be blocked until the 2nd window is no longer visible.


    Edit

    Proof of concept: Change your code from:

      final JFrame frame = new JFrame();
    

    to:

      // rename frame variable to dialog for clarity
      final JDialog dialog = new JDialog();
      dialog.setModalityType(ModalityType.APPLICATION_MODAL);
    

    and it works.


    But again, I'd get rid of unnecessary statics and get rid of doing too much code in the main method. For instance,...

    import javax.swing.AbstractAction;
    import javax.swing.JButton;
    import javax.swing.JComboBox;
    import javax.swing.JDialog;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.JTextField;
    import javax.swing.SwingUtilities;
    
    import java.awt.Dialog.ModalityType;
    import java.awt.Dimension;
    import java.awt.Window;
    import java.awt.event.ActionEvent;
    
    @SuppressWarnings("serial")
    public class MinimalExProgram3 extends JPanel {
       private static void createAndShowGui() {
          MainPanel mainPanel = new MainPanel();
    
          JFrame frame = new JFrame("MinimalExProgram3");
          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();
             }
          });
       }
    }
    
    @SuppressWarnings("serial")
    class MainPanel extends JPanel {
       private static final int PREF_W = 400;
       private static final int PREF_H = PREF_W;
       private JTextField field = new JTextField(8);
       private ComboPanel comboPanel = new ComboPanel();
       JDialog dialog = null;
    
       public MainPanel() {
          field.setFocusable(false);
    
          add(field);
          add(new JButton(new ShowComboAction("Show Combo")));
       }
    
       @Override // make it bigger
       public Dimension getPreferredSize() {
          if (isPreferredSizeSet()) {
             return super.getPreferredSize();
          }
          return new Dimension(PREF_W, PREF_H);
       }
    
       private class ShowComboAction extends AbstractAction {
          public ShowComboAction(String name) {
             super(name);
             int mnemonic = (int) name.charAt(0);
             putValue(MNEMONIC_KEY, mnemonic);
          }
    
          @Override
          public void actionPerformed(ActionEvent e) {
             Window mainWin = SwingUtilities.getWindowAncestor(MainPanel.this);
             if (dialog == null) {
                dialog = new JDialog(mainWin, "Dialog", ModalityType.APPLICATION_MODAL);
                dialog.add(comboPanel);
                dialog.pack();
                dialog.setLocationRelativeTo(null);
             }
    
             dialog.setVisible(true);
    
             // code called here after dialog no longer visible
             String text = comboPanel.getText();
             field.setText(text);
          }
       }
    }
    
    @SuppressWarnings("serial")
    class ComboPanel extends JPanel {
       private static final String[] DESCRIPTION = { "One", "Two", "Three" };
       private int ind;
       private JComboBox<String> combo = new JComboBox<>(DESCRIPTION);
       private String text;
       private SelectionAction selectionAction = new SelectionAction("Select");
       private JButton selectionButton = new JButton(selectionAction);
    
       public ComboPanel() {
          add(combo);
          add(selectionButton);
    
          combo.setAction(selectionAction);
       }
    
       public int getInd() {
          return ind;
       }
    
       public String getText() {
          return text;
       }
    
       private class SelectionAction extends AbstractAction {
          public SelectionAction(String name) {
             super(name);
             int mnemonic = (int) name.charAt(0);
             putValue(MNEMONIC_KEY, mnemonic);
          }
    
          @Override
          public void actionPerformed(ActionEvent e) {
             ind = combo.getSelectedIndex();
             if (ind >= 0) {
                text = combo.getSelectedItem().toString();
             }
             Window win = SwingUtilities.getWindowAncestor(ComboPanel.this);
             win.dispose();
          }
       }
    }