0

I'm finishing my homework in OOP Java. The assignment is to load images on a JFrame, be able to move them around (top layer should be prioritized, it is currently not) and click them to "flip them" (change the source of the image essentially). I'm currently having trouble finding a solution on how to properly "layer" images that are visible on the screen and to prioritize the images on the top first (currently the bottom ones are being prioritized).

I also have issues finding a good way to change the source of the images, as our teacher has prohibited extending the Picture class with Swing.

My first attempt at solving this was saving the information of every individual "Picture" object in an ArrayList. This works to save the position of the images but does not solve my issue with the layering. I also wanted to use JLayeredPane but as I found out, it was harder than I thought as I have yet to find a viable solution this way (I might be missing some obvious facts about how it works).

I'm thinking what probably needs to happen is that I save the "position" of each image in some type of Array, then using this array to print out the images via paintComponent @ ImagePanel. This is currently what I am doing but it does not act as I wish it to. I think my way of loading in the images in the "Picture" class might have something to do with it. I don't have a lot of experience in Java so all of this is new to me.

I don't want to print out all of my codes as I have 4 classes, so I'm going to print out what I feel are the essential methods in each class. If there's something missing that you guys need in order to guide me in the right direction I'll provide that aswell.

draw @ Picture

public void draw(Graphics g, int i) {
        try {
            BufferedImage img = ImageIO.read(new File("images/icon_"+ i +".gif"));
            g.drawImage(img, x, y, null);
        } catch(IOException ie) {
            System.out.println("Could not find images");
        }
    }

mousePressed & mouseDragged @ MouseHandler

public void mousePressed (MouseEvent e) {
        Point point = e.getPoint();

        chosen = imagepanel.locateImage(point);
    }

    public void mouseDragged (MouseEvent e) {
        int x = e.getX();
        int y = e.getY();

        if (chosen != null) {
            imagepanel.moveImage(chosen, x, y);
        }
    }

loadImages & paintComponent @ ImagePanel

private final static int IMAGES = 7;
private ArrayList <Picture> imageCollection = new ArrayList<>();
private Picture im;
Random rand = new Random();

public void loadImages() {
        for(int i=0; i<IMAGES; i++) {
            int x = rand.nextInt(400) + 40;
            int y = rand.nextInt(400) + 60;

            im = new Picture(x,y);

            imageCollection.add(im);
        }
    }

@Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        int i = 0;

        for (Picture im : imageCollection) {
            i++;
            im.draw(g, i);
        }
    }

I expect the images to stack on top of eachother whenever "flipped" (clicked) or moved (dragged). They do not currently do this as they just maintain their "depth" position. I've tried implementing an Image[] without success.

I also have a flip method where I tried using setIcon (I was using ImageIcon instead of Image previously) but this did not really work for some reason.

I also would love for any feedback on the code so far and any improvements that could be made as I always want to improve.

EDIT: I manage to solve my problems, however I'm sure there's a better way to do this.

    public void placeFirst(Picture im) {
        int pos = imageCollection.indexOf(im);
        imageCollection.remove(pos);
        imageCollection.add(0, im);
    }

    public void flipImage(Picture im) {
        im.flip();
        placeFirst(im);
        repaint();
    }

    public void moveImage(Picture im, Point point) {
        im.move(point.x-(im.getWidth(im)/2), point.y-(im.getHeight(im)/2));
        placeFirst(im);
        repaint();
    }

    public Picture locateImage(Point point) {
        for (int i=0; i<imageCollection.size(); i++) {
            Picture im = imageCollection.get(i);

            if (im.fits(point)) {
                return im;
            }
        }
        return null;
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);

        // There probably exists a better and visually nicer way of doing this
        for (int i=imageCollection.size()-1; i>=0; i--) {
            Picture im = imageCollection.get(i);
            im.draw(g);
        }
    }

lemonslayer
  • 171
  • 10
  • 1) For better help sooner, [edit] to add a [MCVE] or [Short, Self Contained, Correct Example](http://www.sscce.org/). 2) One way to get image(s) for an example is to hot link to images seen in [this Q&A](http://stackoverflow.com/q/19209650/418556). E.G. [This answer](https://stackoverflow.com/a/10862262/418556) hot links to an image embedded in [this question](https://stackoverflow.com/q/10861852/418556). – Andrew Thompson Apr 01 '19 at 11:54

1 Answers1

1
chosen = imagepanel.locateImage(point);

Well, we don't know how the locateImage(...) method works, but I would guess you just iterate through the array until you find a match.

So you will always find the same match.

So if you want an image to stack on top you have two issues:

  1. you need to modify the search order so that when you click on an image you move it to position 0 in the ArrayList so it is always found first

  2. but know when you paint images you need to paint images from the end of the ArrayList to the beginning, so the first image in the ArrayList gets painted last.

camickr
  • 321,443
  • 19
  • 166
  • 288
  • Yeah, I realized that I had to start painting them from the end of the List. However, my implementation, albeit working, is very visually ugly. I managed to solve my problem by myself earlier, but I'm very disappointed of my solution lol. (See the edit in my post). – lemonslayer Apr 01 '19 at 15:21