1

I have an image inside a JLabel.

JLabel label = new JLabel(new ImageIcon("C:\\image.jpg"));
label.setSize(300,300);

I want the following functionality.

-I click on a location inside the JLabel (on the image).

-With the mousebutton pressed, I can change the location of the image within the JLabel. (I drag the picture to different positions within the JLabel)

Well, this means that in many instances the picture will be cropped and outside of view.

Please tell me how to implement this functionality?

What are the correct event listeners to add to my JLabel?

ThePrince
  • 818
  • 2
  • 12
  • 26
  • 3
    Very likely you will need to create a class which extends JLabel. – Code-Apprentice Oct 29 '12 at 22:03
  • Why does it need to be a `JLabel` ? – Robin Oct 29 '12 at 22:15
  • Robin, what do you suggest I use for this functionality? JLabel was the first thing that came to mind when thinking about images, but I'm a noob at images, really. – ThePrince Oct 29 '12 at 22:20
  • 1
    You need to add a MouseListener. You also need to create a class, as Code-Guru said, that extends JLabel and overrides paintComponent. Inside the paintComponent, you will need to remove parts of your image on mousePressed. I am working on this and I will post an answer soon. – Coupon22 Oct 29 '12 at 22:32
  • You should probably look at MouseMoationListeners too. – Coupon22 Oct 29 '12 at 22:48

3 Answers3

4

This is a basic example...

It works by dividing the label up into a 3x3 grid, where each cell represents a possible position for the icon.

public class TestMouseDrag {

    public static void main(String[] args) {
        new TestMouseDrag();
    }

    public TestMouseDrag() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException ex) {
                } catch (InstantiationException ex) {
                } catch (IllegalAccessException ex) {
                } catch (UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new DragMyIcon());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    protected class DragMyIcon extends JPanel {

        private JLabel label;

        public DragMyIcon() {

            ImageIcon icon = null;

            try {
                icon = new ImageIcon(ImageIO.read(getClass().getResource("/bomb.png")));
            } catch (IOException ex) {
                ex.printStackTrace();
            }

            label = new JLabel(icon);
            label.setHorizontalAlignment(JLabel.CENTER);
            label.setVerticalAlignment(JLabel.CENTER);

            setLayout(new BorderLayout());
            add(label);

            MouseHandler handler = new MouseHandler();
            label.addMouseListener(handler);
            label.addMouseMotionListener(handler);

        }

    }

    protected class MouseHandler extends MouseAdapter {

        private boolean active = false;

        @Override
        public void mousePressed(MouseEvent e) {

            JLabel label = (JLabel) e.getComponent();
            Point point = e.getPoint();

            active = getIconCell(label).contains(point);
            if (active) {
                label.setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
            } else {
                label.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
            }

        }

        @Override
        public void mouseReleased(MouseEvent e) {
            active = false;
            JLabel label = (JLabel) e.getComponent();
            label.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
        }

        @Override
        public void mouseDragged(MouseEvent e) {
            if (active) {
                JLabel label = (JLabel) e.getComponent();
                Point point = e.getPoint();

                int verticalAlign = label.getVerticalAlignment();
                int horizontalAlign = label.getHorizontalAlignment();

                if (isWithInColumn(label, point, 0)) {
                    horizontalAlign = JLabel.LEFT;
                } else if (isWithInColumn(label, point, 1)) {
                    horizontalAlign = JLabel.CENTER;
                } else if (isWithInColumn(label, point, 2)) {
                    horizontalAlign = JLabel.RIGHT;
                }

                if (isWithInRow(label, point, 0)) {
                    verticalAlign = JLabel.TOP;
                } else if (isWithInRow(label, point, 1)) {
                    verticalAlign = JLabel.CENTER;
                } else if (isWithInRow(label, point, 2)) {
                    verticalAlign = JLabel.BOTTOM;
                }

                label.setVerticalAlignment(verticalAlign);
                label.setHorizontalAlignment(horizontalAlign);

                label.invalidate();
                label.repaint();

            }
        }

        @Override
        public void mouseMoved(MouseEvent e) {
        }

        protected boolean isWithInColumn(JLabel label, Point p, int gridx) {
            int cellWidth = label.getWidth() / 3;
            int cellHeight = label.getHeight();

            Rectangle bounds = new Rectangle(gridx * cellWidth, 0, cellWidth, cellHeight);

            return bounds.contains(p);
        }

        protected boolean isWithInRow(JLabel label, Point p, int gridY) {
            int cellWidth = label.getWidth();
            int cellHeight = label.getHeight() / 3;

            Rectangle bounds = new Rectangle(0, cellHeight * gridY, cellWidth, cellHeight);

            return bounds.contains(p);
        }

        private Rectangle getIconCell(JLabel label) {

            Rectangle bounds = new Rectangle();

            int cellWidth = label.getWidth() / 3;
            int cellHeight = label.getHeight() / 3;

            bounds.width = cellWidth;
            bounds.height = cellHeight;

            if (label.getHorizontalAlignment() == JLabel.LEFT) {
                bounds.x = 0;
            } else if (label.getHorizontalAlignment() == JLabel.CENTER) {
                bounds.x = cellWidth;
            } else if (label.getHorizontalAlignment() == JLabel.RIGHT) {
                bounds.x = cellWidth * 2;
            } else {
                bounds.x = 0;
                bounds.width = 0;
            }
            //if (label.getHorizontalAlignment() == JLabel.TOP) {
            //    bounds.y = 0;
            //} else if (label.getHorizontalAlignment() == JLabel.CENTER) {
            //    bounds.y = cellHeight;
            //} else if (label.getHorizontalAlignment() == JLabel.BOTTOM) {
            //    bounds.y = cellHeight * 2;
            //} else {
            //    bounds.y = 0;
            //    bounds.height = 0;
            //}
            if (label.getVerticalAlignment() == JLabel.TOP) {
                bounds.y = 0;
            } else if (label.getVerticalAlignment() == JLabel.CENTER) {
                bounds.y = cellHeight;
            } else if (label.getVerticalAlignment() == JLabel.BOTTOM) {
                bounds.y = cellHeight * 2;
            } else {
                bounds.y = 0;
                bounds.height = 0;
            }

            return bounds;

        }

    }

}

UPDATED from feedback

This example basically uses a JLayerdPane to allow the repositioning of JLabels within it's container...

public class MoveMe {

    public static void main(String[] args) {
        new MoveMe();
    }

    public MoveMe() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException ex) {
                } catch (InstantiationException ex) {
                } catch (IllegalAccessException ex) {
                } catch (UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new MoveMePane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class MoveMePane extends JLayeredPane {

        public MoveMePane() {
            int width = 400;
            int height = 400;
            for (int index = 0; index < 10; index++) {
                String text = "Label " + index;
                JLabel label = new JLabel(text);
                label.setSize(label.getPreferredSize());

                int x = (int) Math.round(Math.random() * width);
                int y = (int) Math.round(Math.random() * height);
                if (x + label.getWidth() > width) {
                    x = width - label.getWidth();
                }
                if (y + label.getHeight() > width) {
                    y = width - label.getHeight();
                }
                label.setLocation(x, y);
                add(label);
            }

            MoveMeMouseHandler handler = new MoveMeMouseHandler();
            addMouseListener(handler);
            addMouseMotionListener(handler);
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(400, 400);
        }
    }

    public class MoveMeMouseHandler extends MouseAdapter {

        private int xOffset;
        private int yOffset;
        private JLabel draggy;
        private String oldText;

        @Override
        public void mouseReleased(MouseEvent me) {
            if (draggy != null) {
                draggy.setText(oldText);
                draggy.setSize(draggy.getPreferredSize());
                draggy = null;
            }
        }

        public void mousePressed(MouseEvent me) {
            JComponent comp = (JComponent) me.getComponent();
            Component child = comp.findComponentAt(me.getPoint());
            if (child instanceof JLabel) {
                xOffset = me.getX() - child.getX();
                yOffset = me.getY() - child.getY();

                draggy = (JLabel) child;
                oldText = draggy.getText();
                draggy.setText("What a drag");
                draggy.setSize(draggy.getPreferredSize());
            }
        }

        public void mouseDragged(MouseEvent me) {
            if (draggy != null) {
                draggy.setLocation(me.getX() - xOffset, me.getY() - yOffset);
            }
        }
    }
}
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • This is a very useful example. Do you know why it only works on the first drag and drop? Hmm, I'll look over the code and see if it is a quick fix. Thank you for your awesome example. I'll try to adapt it to the needs of my program and see how it goes :) – ThePrince Oct 30 '12 at 23:00
  • @user1784129 Probably because I've not slept in 3 days :P - I've fixed the bug, it should work ... better ;) – MadProgrammer Oct 30 '12 at 23:13
  • I modified your code a little bit and got it working exactly as intended. Your code showed me what listeners to add and also how to do the dragging. Thanks for your help. – ThePrince Oct 31 '12 at 17:53
3

First, I would recommended using a layout instead of setLayout(null) and setBounds(). Secondly, seperate the ImageIcon from the JLabel. Finally, set the JLabel and the ImageIcon as fields instead of a local variable.

You need to add a MouseListener and a MouseMotionListener.

label.addMouseMotionListener(new MouseAdapter()
{
    public void mouseMoved(MouseEvent arg0)
    {
        if(clicked)
        {
            label.x++
            label.y++
            label.repaint();
        }
    }
});

label.addMouseListener(new MouseAdapter()
{
    public void mousePressed(MouseEvent arg0)
    {
        clicked = !clicked;
    }
});

(Sorry for being wordy beforehand)

This causes the image of the label to appear where the label is, and when you your mouse over it it will move diagonal southeast. I created a new label class, where I override paintComponent and added in there a paint image icon method, where the x and y are variables. The idea will be to calculate a center point on your label, then move the x position of the image west if going west of that point (x--), south if going south(y--), ect. This would only move your image inside the label. If your mouse if outside of the label, the moving would stop. If parts of the image are outside of the label, then that part will not be shown. I would override paint compoent in your label class and move the image over, then set the icon for each movement.

public class Label1 extends JLabel
{
    public int x;
    public int y;
    ImageIcon imageIcon = new ImageIcon("path");

    public void paintComponent(Graphics g)
    {
        super.paintComponent(g);
//No setLocation(x, y) method exists for an image icon or an image. You are on your own on this
        imageIcon.setLocation(x, y);
        label.setIcon(imageIcon);
    }
}
Coupon22
  • 395
  • 8
  • 24
  • I am going to test this. Thank you for taking your time to write this. I will work on the setLocation() for the image icon, and see if I find a workaround. Be back in a moment. – ThePrince Oct 30 '12 at 20:19
  • Okay... maybe I should place the JLabel in a JPanel, and move it within the JPanel? I'll try coding this up and see if it works. Thanks for these ideas. – ThePrince Oct 30 '12 at 21:01
1

This modified example is based on MadProgrammer's code.

It shows the behavior I described in my original post. Thank you all for your valuable help, especially MadProgrammer and Coupon22. Try it out.

import java.awt.*;
import javax.swing.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseAdapter;

public class TestMouseDrag {

public static void main(String[] args) {
    new TestMouseDrag();
}

public TestMouseDrag() {
    EventQueue.invokeLater(new Runnable() {
        @Override
        public void run() {
            try {
                UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
            } catch (ClassNotFoundException ex) {
            } catch (InstantiationException ex) {
            } catch (IllegalAccessException ex) {
            } catch (UnsupportedLookAndFeelException ex) {
            }

            JFrame frame = new JFrame();
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setLayout(new BorderLayout());
            frame.add(new DragMyIcon("C://image.jpg"));
            frame.pack();
            frame.setSize(500,500);
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        }
    });
}

protected class DragMyIcon extends JPanel {

    public static final long serialVersionUID = 172L;
    private JLabel label;

    public DragMyIcon(String path) {
        setLayout(null);

        ImageIcon icon = null;

        icon = new ImageIcon(path);

        label = new JLabel(icon);
        label.setBounds(0,0,icon.getIconWidth(), icon.getIconHeight());
        setBounds(0,0,icon.getIconWidth(), icon.getIconHeight());
        label.setHorizontalAlignment(JLabel.CENTER);
        label.setVerticalAlignment(JLabel.CENTER);

        add(label);

        MouseHandler handler = new MouseHandler();
        label.addMouseListener(handler);
        label.addMouseMotionListener(handler);

    }

}

protected class MouseHandler extends MouseAdapter {

    private boolean active = false;
    private int xDisp;
    private int yDisp;

    @Override
    public void mousePressed(MouseEvent e) {
        active = true;
        JLabel label = (JLabel) e.getComponent();

        xDisp = e.getPoint().x - label.getLocation().x;
        yDisp = e.getPoint().y - label.getLocation().y;

        label.setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
    }

    @Override
    public void mouseReleased(MouseEvent e) {
        active = false;
        JLabel label = (JLabel) e.getComponent();
        label.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
    }

    @Override
    public void mouseDragged(MouseEvent e) {
        if (active) {
            JLabel label = (JLabel) e.getComponent();
            Point point = e.getPoint();
            label.setLocation(point.x - xDisp, point.y - yDisp);
            label.invalidate();
            label.repaint();

        }
    }

    @Override
    public void mouseMoved(MouseEvent e) {
    }
}

}

ThePrince
  • 818
  • 2
  • 12
  • 26
  • I'd suggest you use a JLayredPane over using a null layouut – MadProgrammer Oct 31 '12 at 19:06
  • And I'm just going to be nit picky, but this isn't what your question asked for ;) you asked for a means to drag an icon within the context of label, not drag the label it self, that would have begin much easier ;P – MadProgrammer Oct 31 '12 at 19:08
  • That is true. I guess it is just pretending to show the functionality. Also, is there something inherently wrong with null layout? – ThePrince Oct 31 '12 at 22:35
  • 1
    `null` layouts are generally discouraged as they can cause no end of problems and increase a programs level of complexity (normally without any gain). You could have a look at [DragLayout](http://tips4java.wordpress.com/2011/10/23/drag-layout/) which is designed to make this process simpler. Don't get me wrong, there are times that a `null` layout can be useful, but you should explore all your available options before settling on it - IMHO – MadProgrammer Oct 31 '12 at 23:06
  • Do you have a modification you would make, to make the image draggable without null layout? The drag has to be precise, rather, than squares on a grid, unless you make the grid so small that it is more like points? It's almost there :) – ThePrince Nov 02 '12 at 14:58
  • That's an open question. How would I modify my original example, you can't. The position of the icon within the label is controlled by the label it self. How would I modify you example, check [here](http://stackoverflow.com/questions/13145798/jlabels-that-store-imageicons-are-returned-back-to-original-location-when-the/13146002#13146002) for an implementation I've already done ;) – MadProgrammer Nov 02 '12 at 20:37
  • The checkmarked answer should drag smoothly rather than on a grid. But I really want to give you the checkmark so maybe you could make it drag smoothly just so I can give you the checkmark hehe :) Of course I am dragging the label itself, but if you put it in a JPanel it is kind of serving the same purpose :) – ThePrince Nov 02 '12 at 22:50