0

I am having problem accessing the variable int i inside the inner class Code:

public class OnColumnSelectPanel {

JFrame jFrame;
JPanel mainJPanel;
//JPanel jPanel1;
//JTextField jTextField;
//JButton jButton;
//JComboBox jComboBox [];
MigLayout layout;
MigLayout frameLayout;
//column names
ColumnNames cn = new ColumnNames();
List<String> listedColumnNames = cn.getColumnNames();
String columnNames[] = listedColumnNames.toArray(new String[0]);

public OnColumnSelectPanel(int n) {

    //jPanel1 = new JPanel();
    jFrame = new JFrame("Create Structure of Columns");
    // mainJPanel = new JPanel();
    layout = new MigLayout("flowy", "[center]rel[grow]", "[]10[]");
    frameLayout = new MigLayout("flowx", "[center]rel[grow]", "[]10[]");
    //mainJPanel.setLayout(new BoxLayout(mainJPanel, BoxLayout.X_AXIS));
    //MigLayout mainJPanelLayout = new MigLayout("flowy", "[]rel[grow]", "[]5[]");

    // declare & initialize array
    JPanel jPanel[] = new JPanel[n];
    JComboBox jComboBox[] = new JComboBox[n];
    JButton jButton[] = new JButton[n];
    final int num = 0;
    for (int i = 0; i < n; i++) {

        //assign array
        jComboBox[i] = new JComboBox(columnNames);
        jButton[i] = new JButton("add Sub Heading");
        jPanel[i] = new JPanel();
        System.out.println("Loop number: " + i);

        jButton[i].addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent ae) {

                for (int j = 0; j < n; j++) {
                    if (j <= n) {
                        jComboBox[j] = new JComboBox(columnNames);
                        jPanel[j].add(jComboBox[j]);
                        jFrame.revalidate();
                    } else {
                        JOptionPane.showMessageDialog(null, "You have exceeded your limit");
                    }
                }

            }
        });
        //set layout
        jPanel[i].setLayout(layout);
        //jPanel[i].setPreferredSize(new Dimension(50, 400));
        //mainJPanel.setLayout(mainJPanelLayout);
        jFrame.setLayout(frameLayout);
        System.out.println(" height " + jPanel[i].getHeight());
        jPanel[i].add(jComboBox[i], new CC().newline());
        //jPanel.add(jTextField);
        jPanel[i].add(jButton[i]);
        //mainJPanel.add(jPanel[i], "spany");
        jPanel[i].repaint();

        jFrame.add(jPanel[i]);
        jFrame.pack();
        jPanel[i].revalidate();
        jFrame.revalidate();
        //mainJPanel.revalidate();
        //jFrame.revalidate();

    }
    //mainJPanel.setSize(600, 400);

    //jFrame.add(jPanel1);
    jFrame.setVisible(true);
    jFrame.setSize(600, 400);
    jFrame.setAlwaysOnTop(true);
    jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}

Output Frame

As you can see the output image. The problem here is that when i click on the add subheading button, combobox is added to every jpanel. this is because i can;t pass the value i to the inner class. It would be interesting to know possible solutions for this.

FYI I am using Mig Layout.

Thanks in advance.

  • 2
    1) For better help sooner, post a [MCVE] or [Short, Self Contained, Correct Example](http://www.sscce.org/). 2) Words typed in all lower case are hard to read, like trying to listen to someone who is mumbling. Please use an upper case letter at the start of sentences, for the word I, and proper names like `ArrayList` or Oracle. – Andrew Thompson Jun 22 '18 at 10:32
  • Break your anonymous class out into an inner class - pass it ALL the information it needs in order to perform the required task (because I'm at a lost to understand what's really going on) – MadProgrammer Jun 22 '18 at 10:38
  • Also, consider using a custom component which maintains all the required information internally to it, rather then a bunch of disconnected arrays – MadProgrammer Jun 22 '18 at 10:40
  • I am really sorry for such bad format. I was In hurry. I'll take care of this from next time. Really Sorry! – Dinesh Solanki Jun 23 '18 at 04:36

1 Answers1

0

Only effectively final variables can be accessed from anonymous classes. i is modified by the loop, so it is not effectively final.

A workaround would look like this:

for (int i = 0; i < n; i++) {
   ...

  final int effectivelyFinal = i;
  jButton[i].addActionListener(new ActionListener() {

    @Override
    public void actionPerformed(ActionEvent ae) {
      ...
      // use effectivelyFinal instead of i
    });
}

But as other suggested, it would be way better to extract the anonymous class into a real class and pass all required parameters using the constructor. This can look like this:

class MyListener implements ActionListener {

    private final int index;

    // add more fields for other required parameters

    public MyListener(int index) {
        this.index = index;
    }

    @Override
    public void actionPerformed(ActionEvent e) {
      // use index    
    }
}

Usage:

jButton[i].addActionListener(new MyListener(i));
micha
  • 47,774
  • 16
  • 73
  • 80