0

I am having difficulties drawing all images in a ArrayList to the canvas.

I was first able to correctly draw all the images using just one path name for all images in the code below:

 private ArrayList<Module> list;
 //... some code loading in modules
 public void loadModuleImages() {
    addModuleImage = new Image("images/Plain.jpg");
    addModuleImage.setVisible(true);
    addModuleImage.setVisible(true);    
        addModuleElement = ImageElement.as(addModuleImage.getElement());
    addModuleImage.addLoadHandler( new LoadHandler(){
        public void onLoad(final LoadEvent event){

        for(int i = 1; i<=list.size()+1;i++){
        context.drawImage(addModuleElement, list.get(i-1).getX(),list.get(i-1).getY()); 
            }
        }
    });
canvas.setVisible(true);
addModuleImage.setVisible(false);
RootPanel.get().add(addModuleImage);
}

Now when I start to use an ArrayList to display all the images I end up drawing only the last image to the screen. Using the code below:

public void loadModuleImages() {
    final ArrayList<Image> images = new ArrayList<Image>();
    final ArrayList<ImageElement> imagesE = new ArrayList<ImageElement>();
    for(int i = 1; i<=list.size()+1;i++){
        images.add(new Image(list.get(i-1).getImageName()));
        x = list.get(i-1).getX();
        y = list.get(i-1).getY();
        images.get(i-1).setVisible(true);   
        imagesE.add(ImageElement.as(images.get(i-1).getElement()));
        addModuleElement = imagesE.get(i-1);
        images.get(i-1).addLoadHandler( new LoadHandler(){
            public void onLoad(final LoadEvent event){
                context.drawImage(addModuleElement, x, y);  

            }
        });
        canvas.setVisible(true);
        images.get(i-1).setVisible(false);
        RootPanel.get().add(images.get(i-1));
    }

}

The Module class contains accessor methods for the x position (getX()),y position getY(), and image name (getImageName()). For debugging reasons all the images are all "images/Plain.jpg". It appears something in my loop is making the last image get drawn over and over, not switching to the next image.

Please help me figure out how to correctly load all the images or any suggestions about a different way to approach my problem. Thank you

studnet
  • 1
  • 1

1 Answers1

0

Excerpt from your code

    x = list.get(i-1).getX();
    y = list.get(i-1).getY();
    images.get(i-1).setVisible(true);   
    imagesE.add(ImageElement.as(images.get(i-1).getElement()));
    addModuleElement = imagesE.get(i-1);
    images.get(i-1).addLoadHandler( new LoadHandler(){
        public void onLoad(final LoadEvent event){
            context.drawImage(addModuleElement, x, y); 
    //...

I assume then it follows that your class has three fields:

private int x;
private int y;
private ImageElement addModuleElement;

Lets add some quick logging and try running the code in our heads:

    log("setting up step #" + i);
    x = list.get(i-1).getX();
    y = list.get(i-1).getY();
    log("x,y updated: " + x + "," + y); 
    images.get(i-1).setVisible(true);   
    imagesE.add(ImageElement.as(images.get(i-1).getElement()));
    addModuleElement = imagesE.get(i-1);
    images.get(i-1).addLoadHandler( new LoadHandler(){
        public void onLoad(final LoadEvent event){
            log("element loaded #" + i + ", x/y = " + x + "/" + y);
            context.drawImage(addModuleElement, x, y);

Remembering that image downloading is asynchronous, we would expect to see logging come out of that code like this:

setting up step #1
x,y updated: 10,10
setting up step #2
x,y updated: 20,20
setting up step #3
x,y updated: 30,30

Then a pause while the images are downloaded

element loaded #1, x/y= 30/30
element loaded #2, x/y= 30/30
element loaded #3, x/y= 30/30

Whats happening is that you reassign x, y, addModuleElement every step through the loop, so that when the event handlers eventually run, they all have the data from the very last item.

Instead, use those values directly, and get rid of the fields:

    final int x = list.get(i-1).getX();
    final int y = list.get(i-1).getY();
    images.get(i-1).setVisible(true);   
    imagesE.add(ImageElement.as(images.get(i-1).getElement()));
    final ImageElement addModuleElement = imagesE.get(i-1);
    images.get(i-1).addLoadHandler( new LoadHandler(){
        public void onLoad(final LoadEvent event){
            context.drawImage(addModuleElement, x, y); 

This way each LoadHandler will have its own copy of those variables, and they won't all be trying to share the same ones.

(see also the classic GWT thread, "That's Not Async" - though this is addressing RPC, its the same general problem that you are facing.)

Colin Alworth
  • 17,801
  • 2
  • 26
  • 39