Reputation: 890
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?
Upvotes: 1
Views: 9172
Reputation: 347184
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);
}
}
}
}
Upvotes: 4
Reputation: 394
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);
}
}
Upvotes: 3
Reputation: 890
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) {
}
}
}
Upvotes: 1