1

I'm trying to figure out how to access my different images, drawn with paintComponent, (using JLabels is not allowed in the assignment) in my events.

When dragging, I only want one image to move with my mouse drag and I cant seem to access "current image" with e.getSource().

My paintComponent will move all (3) images at the same time at the moment.

My question is: how to get hold of a single ImageIcon with my mouseDragged?

public class PhotoPanel extends JPanel implements MouseListener, MouseMotionListener {

private java.util.List<ImageIcon> myList = new ArrayList<>();
private int mx, my;

private ImageIcon image1 = new ImageIcon("src/resources/gira.gif");
private ImageIcon image2 = new ImageIcon("src/resources/stru.gif");
private ImageIcon image3 = new ImageIcon("src/resources/back.gif"); 

public PhotoPanel()
{
    setBackground(Color.GREEN);

    myList.add(image1);
    myList.add(image2);
    myList.add(image3);

    //Is this a problematic way of doin it?
    addMouseMotionListener(this);

}

public void paintComponent (Graphics g) {

    super.paintComponent(g);

    for (ImageIcon i : myList)
    {
       g.drawImage(i.getImage(), mx, my, this);
    }    
}


@Override
public void mouseDragged(MouseEvent e) {

    //if(e.getSource == image1)
    //{
    //    Manipulate single picture, but not working this way  
    //}
    mx = e.getX();
    my = e.getY();

    repaint();
    }    
}
Vatchi
  • 13
  • 4

3 Answers3

4

I'm trying to figure out how to access my different images, drawn with paintComponent, (using JLabels is not allowed in the assignment) in my events

Since you can't use JLabels and if you want to get the current image being selected. You will have to iterate through the list of images add check which one is selected.

Currently you keep a list of ImageIcon, and there is no direct means to get the bounds of ImageIcon to check for selection.

If I were you, I will add a property (bounds) to the current ImageIcon to facilitate us to check whether an image is being clicked by the mouse:

class MyImages extends Rectangle
{
    private ImageIcon image;  //personally, I prefer to use BufferedImage here

    public MyImages(int x, int y, int width, int height){
        setBounds(x, y, width, height);
    }

    //getters & setters for image not shown

    public void draw(Graphics g){
        g.drawImage(image.getImage(), x, y, width, height, null);
    }

    //Check if current image is selected:
    public boolean isSelected(int xCoord, int yCoord){
        return (this.contains(xCoord, yCoord))
    }
}

In your PhotoPanel class:

//Crate a list of MyImage instead of ImageIcon
ArrayList<MyImage> myList = new ArrayList<MyImage>();
MyImage selectedImage;

In you MouseMotionListener class:

@Override 
public void mousePressed(MouseEvent e){

    //To get the image which is selected:
    for(MyImage img : myList)
        if(img.isSelected(e.getX(), e.getY())){  //if mouse clicks on this image
            selectedImage = img;    
            break;
        }
}

@Override
public void mouseDragged(MouseEvent e){
    if(selectedImage != null){
        selectedImage .setLocation(e.getX()-(pieceWH/2), e.getY()-(pieceWH/2));
        repaint();
    }
}

I maintain an instance call the selectedImage, and on mouse drag, we will change the location of selectedImage only. Hence only the last selected image will move.


In your paintComponent(g) method, you could just use .draw(g) if you created a customized Image class like MyImage:

@Override
protected void paintComponent(Graphics g){
    super.paintComponent(g);
    for (MyImage i : myList)
        i.draw(g);
}

This is a jig-saw puzzle I did with the same technique in the past:

enter image description here

user3437460
  • 17,253
  • 15
  • 58
  • 106
  • @Vatchi You can take a look at my solution. – user3437460 Mar 22 '16 at 17:26
  • 1
    Good one. An effort which definitely deserve upvotes. – rdonuk Mar 22 '16 at 20:57
  • @user3437460 You don't need to leave a comment to the OP, they are notified when a new answer is added – MadProgrammer Mar 22 '16 at 21:00
  • @MadProgrammer Do you mean.. *no need* to leave... ? – user3437460 Mar 22 '16 at 21:02
  • @user3437460 I mean it's too early in the morning for me to be leaving comments :P – MadProgrammer Mar 22 '16 at 21:03
  • @user3437460 That sure looks juicy! Theres still some things I dont quite understand though. Like getters/setters, we havent covered yet, in MyImages class, Is it something like this i should be doin: `public void addImage(ImageIcon image) { this.image = image; }` And how do I add my ImageIcons to myList in PhotoPanel now? Create a new MyImages object and call the above method addImage on it? And lastly what are these variables: (pieceWH/2), (pieceWH/2)? Thanks alot! :) – Vatchi Mar 23 '16 at 13:03
  • @Vatchi `pieceWH` is optional. They are your individual image's dimension. I put it there so that your mouse cursor will be at the centre of the image which you clicked. Yes you are right, `getters` & `setters` are just methods in your class to access the class properties, e.g. `public MyImage getImage(){return image;}` You are right again on adding MyImages to the list in `PhotoPanel`. Just add it like how you add ImageIcon. But now you have your own customized Image call `MyImage`. So it will be something like `myList.add(new MyImage());` – user3437460 Mar 23 '16 at 13:25
  • @user3437460 I'm getting the images to show using your advise although they wont move, I think the problem is I'm still doing something wrong with my Listeners, they seems to be blocking each other out in some way. My custom Listener class: `class MouseTestListener implements MouseListener, MouseMotionListener` My Listerners: `MouseTestListener listener = new MouseTestListener(); addMouseListener(listener); addMouseMotionListener(listener);` – Vatchi Mar 23 '16 at 14:19
  • @Vatchi What you did is correct. There should be other reasons. You can test your codes in portions. For example test whether it can select the image by clicking first, then followed by checking whether the selected image can change location when you drag your mouse. Also make sure you call repaint() to update the screen. – user3437460 Mar 23 '16 at 14:47
  • 1
    @user3437460 Okay I got it working, was reading some more about MouseEvents and they seem to be a bit special when using both. I fixed it doin: `addMouseListener(new MouseInputAdapter() { public void mousePressed(MouseEvent e) { for(MyImages img : myList) if(img.isSelected(e.getX(), e.getY())){ selectedImage = img; break; } } });` I dont rly know why this is working but it seems to be separating them and it works. Thank you so much for your patience and good answers! – Vatchi Mar 23 '16 at 15:39
1

Do not paint your images, use JLabels for displaying them.

JLabel imageLabel1 = new JLabel(image1);

If you add this to your panel it will show your image. You can reach your image by reaching labels. By the way, add your listener to all labels so getSource() will return you the related label.

rdonuk
  • 3,921
  • 21
  • 39
  • Is it possible to move the images the way OP asks if they are JLabels? – Laurel Mar 22 '16 at 15:55
  • Yes if you change positions of the JLabels image will be moved. – rdonuk Mar 22 '16 at 16:06
  • (1+) @Laurel, yes it is easier then just drawing an image because you just add the listener to the label and then set the location of the label as you drag it. Of course you also need to use a null layout on the panel so the label can be painted in any location. – camickr Mar 22 '16 at 16:08
  • Hey thanks for reply, I'm aware this is probably the best solution, and I've messed around with it. Allthough the asignment is to solve this without using this type of method (JLabels, JButtons etc), instead painting them directly with paintComponent. This is my bad since I didnt write it in description. Thanks again though! – Vatchi Mar 22 '16 at 16:10
  • @rdonuk Can you stack the images if they are in JLabels (like you can do with a canvas)? – Laurel Mar 22 '16 at 16:18
  • 1
    @Laurel, yes. Swing uses the "ZOrder" to determine the order in which components are painted. – camickr Mar 22 '16 at 16:23
  • @Vatchi, `This is my bad since I didnt write it in description` - well then update the question so all the information relevant to the question if found in the question, not in the comments. – camickr Mar 22 '16 at 16:23
  • 1
    @camickr I guess for this project, (ignoring the paintcomponent requirement) JLabels work fine. If you need more control over the images, such as for a game, I would think paintcomponent is better, right? – Laurel Mar 22 '16 at 16:29
0

I'm seeing problems in several parts of the code. First of all, your images will always be drawn one on top of the other because

for (ImageIcon i : myList)
{
   g.drawImage(i.getImage(), mx, my, this);
}

mx and my are used for all the images. So you need each image to have its own coordinates.

The other part you're missing is code to determine what image is under the mouse when it is first clicked. You'll probably need to get the width and height of the images (and then calculate where the other corner is), but, after that, it's simple math to determine if the click x y is within the bounds of a rectangular image. Note that you will need to determine this for all three of the images.


The thing about getSource() that you need to realize is it returns the implicit parameter in the line addMouseMotionListener(this);

It's also a bit weird that your JPanel listens to itself.

Laurel
  • 5,965
  • 14
  • 31
  • 57
  • "You'll probably need to get the width and height of the images (and then calculate where the other corner is)" is probably my solution! Whats wrong with "addMouseMotionListener(this);", should I make a custom listener? what would be the differens? Thanks a bunch! :) – Vatchi Mar 22 '16 at 16:12
  • @Vatchi I've never seen it written this way is all (for what you're doing, it's ok). Personally, I would declare an inner/anonymous class. Or use a lambda expression (although likely you won't be taught these). If you want to add another listener that's different from the first, you'll need to have it declared separately. – Laurel Mar 22 '16 at 16:22