0

I posted this question earlier in a much larger form, and hope to post it again in a way that allows the community to help me better, by dumping less information on you all.

Fundamentally, I have this code, explained below:

for(JMenuItem x : chem3_x_y){
  x.addActionListener(new ActionListener(){
    public void actionPerformed(ActionEvent k) {
      new SwingImplementation(1, tt+1);
    }
  }); 
  gEleven[6].add(x);
  tt++;
}
tt=0;

First, I cycle through all of the JMenuItem-s in the array chem3_x_y

Then, I add an ActionListener to 'x', or each item of the array, which creates a new SwingImplementation with the arguments of 1, and the variable 'tt'

Following this, the JMenu gEleven receives the JMenuItem in question, I then increase tt by 1.

The purpose of the above code is to automate the process of adding JMenuItems to gEleven, and ActionListeners to each Menu Item.

The problem, the argument passed for the variable 'tt' is always the same, 1, as if the action listener with the argument for 'tt' of 1 is applied to every JMenuItem - why could that be, and how can I use the ever-increasing tt to create one ActionListener per JMenuItem, with the argument of (1, tt) without tt always being 1

Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
William Brun
  • 353
  • 2
  • 17
  • Your code formatting is very bad making it very difficult for us to understand your code. I've fixed it as best I can. – Hovercraft Full Of Eels Oct 28 '13 at 01:32
  • For better help sooner, post an [SSCCE](http://sscce.org/). I believe you've already been advised that, as well as to use more sensible attribute names. If you're ignoring our answers & suggestions, maybe *we* should ignore *your* questions. – Andrew Thompson Oct 28 '13 at 01:35
  • I suspect that your problem lies elsewhere, that you're going to need to do a bit of debugging. – Hovercraft Full Of Eels Oct 28 '13 at 01:35
  • @Andrew, I would prefer you didn't - I have tried to make one of those, but my program is huge and I can't cut very much out without rendering it non-functional, and what do you mean, respectfully I assure you, by sensible names, I have no longer named my variables after numbers, what more could there be to do? – William Brun Oct 28 '13 at 01:42
  • Another thing - could someone just tell me if my creation of the ActionListener could be the cause of my problem -- since they are all named "k" could the first one overlap over all of the other ones? Is that not how it works? – William Brun Oct 28 '13 at 01:44
  • 1
    ????? I have no idea what you just asked. Again, I believe that your posted code is not causing your problem. I agree with Andrew, that you must put some effort into isolating your error. Also, and again, if you post code here for us to review, put just a little effort in towards formatting it well. We're volunteers and that's certainly not asking too much of you. – Hovercraft Full Of Eels Oct 28 '13 at 01:59

2 Answers2

3

Your problem is that tt is not incremented until the listener is invoked. While your action listener code is inline, in fact, it does not all run synchronously - actionPerformed() is not called until the action listener is invoked. So tt never changes while you're looping.

What you want is something like this:

class MyListener implements ActionListener {
  private final int tt;

  MyListener (int tt) { 
    this.tt = tt;
  }

  public void actionPerformed(ActionEvent k) {
     new SwingImplementation(1, tt+1);
  }
}

for(JMenuItem x : chem3_x_y){
  x.addActionListener(new MyListener(tt++)); 
  gEleven[6].add(x);
}

so that you're incrementing tt and storing the result in a final field tied to the listener that needs that value.

Tim Boudreau
  • 1,741
  • 11
  • 13
  • Good guess, absent the declaration of `tt`. – trashgod Oct 28 '13 at 02:27
  • 1
    It had to be on the class that contained the method or some parent or containing class of that, or it would have had to be final to be visible in the inner class, in which case it could never have been incremented. – Tim Boudreau Oct 29 '13 at 03:39
2

Edited: Instead of tt + 1, you probably meant tt++. I can't tell from the code posted. Maybe, look for a tt that shadows the intended variable. Based on this example, the corresponding code below uses ++i. Also consider using Action to encapsulate your listener.

image

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.io.File;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JToolBar;

/**
 * @see https://stackoverflow.com/a/19626219/230513
 * @see https://stackoverflow.com/questions/4038605
 */
public class FileMenu {

    public static void main(String[] args) {

        EventQueue.invokeLater(new Runnable() {

            public void run() {
                new FileMenu().create();
            }
        });
    }

    void create() {
        File userDir = new File(System.getProperty("user.dir"));
        File[] files = userDir.listFiles();

        JMenu menu = new JMenu("Recent Files");
        JToolBar toolBar = new JToolBar(JToolBar.VERTICAL);
        JLabel label = new JLabel(" ", JLabel.CENTER);
        int i = 0;
        for (File f : files) {
            if (f.isFile() && !f.isHidden()) {
                RecentFile rf = new RecentFile(f, label, ++i);
                menu.add(new JMenuItem(rf.getAction()));
                toolBar.add(rf);
            }
        }
        JMenuBar menuBar = new JMenuBar();
        menuBar.add(menu);

        JFrame f = new JFrame("FileMenu");
        f.setJMenuBar(menuBar);
        f.add(toolBar, BorderLayout.CENTER);
        f.add(label, BorderLayout.SOUTH);
        f.pack();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }
}

class RecentFile extends AbstractAction {

    private final File file;
    private final JLabel label;

    public RecentFile(final File file, final JLabel label, int i) {
        this.file = file;
        this.label = label;
        this.putValue(Action.NAME, String.valueOf(i) + " " + file.getName());
        this.putValue(Action.SHORT_DESCRIPTION, file.getAbsolutePath());
    }

    public void actionPerformed(ActionEvent e) {
        label.setText(file.getName());

    }

    public Action getAction() {
        return this;
    }
}
Community
  • 1
  • 1
trashgod
  • 203,806
  • 29
  • 246
  • 1,045