tags:

views:

490

answers:

3

I am writing an Eclipse Plugin that opens a file and displays all the images contained within the file. This image display is part of a GUI application. Each image is rendered by associating it with an SWT Canvas widget. When I open the file I have all the information I need to determine the number of images I will have to display. I though it would make sense to create all the Canvas objects, one after another and store each Canvas object in some type of array like data structure. Every file I open with have a different number of images to display. I decided to use an ArrayList.

I proceed as follows: I create a Canvas object for each image and store all of the Canvas objects in a ArrayList. Here's the problem: Each Canvas object has a PaintListener and MouseListener associated with it - for resizing and detecting if an image has been 'clicked.' I am creating all the Canvas objects in a 'for loop' - which includes assigning a PaintListener and MouseListener to each Canvas object, like so:

`

//
// Assume the following ArrayLists have been defined:
// myCanvases, myImages, and myFrames
//

for (int i = 0; i < numberOfImages; i++) {

    canvas = new Canvas(getMyComposite(), SWT.BORDER | 
        SWT.NO_MERGE_PAINTS | SWT.NONE );

    canvas.setLayoutData(getMyGridData());

.
    .
    .

    canvas.addPaintListener(new PaintListener() {
    public void paintControl(final PaintEvent event) {
        if (myImages.get(i) != null) {
                myImages.get(i).dispose();
                event.gc.drawImage(mySceneImages.get(element), 0, 0);
 }
    }
});

    currentCanvas.addMouseListener(new MouseAdapter() {
    @Override
    public void mouseUp(MouseEvent event) {
        getVideo().setCurrentFrame(myFrames.get(i).getFrameNumber());
       }
    });

    canvas.setVisible(true);

        myCanvases.add(i, canvas);


} // End for (int i = 0; i < numberOfScenes; i++)

`

The Problem: The variable 'i' is used to determine which element to access in the different ArrayLists in the PaintListener and MouseListener. Note I am using 'i' for illustrative purposes here. I realize the variable 'i' defined in the 'for loop' cannot be used in the inner classes of the Listeners. Anyway...... When the Listeners receive an event, whatever variable I do use to attempt to access a specific element of an ArrayList contains it's present value, not the value when the Listeners were defined.

How can I get around this in Java? What I literally need is code in the definition of each Listener that essentially says equates to:

`

myCanvases.get(7); // or whatever the for loop iteration is for that specific object);

// Not

myCanvases.get(i); // - which will contain the present value of i;

`

when the Listener executes.

Any ideas would be appreciated.

Thanks.

+5  A: 

You could just add the object to the constructor of the PaintListener.

E.g

class MyPaintListener implements PaintListener
{
 Image image;
 MyPaintListener(Image image)
 { 
    this.image = image;
 }
 void paintControl(...)
 {  
     do stuff with image.
 }
}
Kire Haglin
Same as Robin, I was beaten :)
Olivier
Worked like a charm. Thanks.
Dr. Faust
A: 

Can't you just use a temporary final var:

final JFrame f = new JFrame();
f.setLayout(new FlowLayout());
for (int i = 0; i < 10; i++) {
  final int curIdx = i;
  JButton btn = new JButton("Btn: " + i);
  btn.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
      JOptionPane.showMessageDialog(f, "Item: " + curIdx);
    }
  });
  f.add(btn);
}
f.pack();
f.setVisible(true);

The listeners all fire events based upon the value of the var at the time of declaration, which sounds like what you want.

jsight
That is exactly what I want, but it doesn't seem to working when I try coding it like your example.
Dr. Faust
I'd have to see an example of what you are doing that is causing this approach to fail. I don't really see how it would do anything other than display the var at instantiation time.
jsight
+1  A: 

Use inner classes instead of an anonymous inner class and pass the objects into the constructor. The variable you are using in the anon class is not stored in the object, so it will reference it's value in the outer class when called.

Robin
Beaten to the punch by Kire, with a code example.
Robin
I think it's a tie because he illustrated by giving and example and you gave a good explanation. This jist being that I needed to store the variable in the PaintListener | MouseAdapter object. Thanks for your help.
Dr. Faust