The program is an animation that creates a car and/or truck icon on the screen. The way I have it now it isn't working correctly. Specifically, the program is not clicking and dragging right. If one object is not-selected, once clicked on, it will become bolder to show that it is selected. From there we want to be able to drag it and the program will redraw the image wherever the mouse goes. If the image is un-selected, when I click and drag it, it works fine. The problem I am having is if the image is already selected. If the image is already selected, when I move the mouse over to it and click on it in order to move it to a different position, instead of moving, it is deselected instead so no movement occurs. Here is the code for the mousePressed and mouseDragged events. I think that is where the problem is, but I'm not sure what is causing it.
addMouseListener(new
MouseAdapter()
{
public void mousePressed(MouseEvent event)
{
mousePoint = event.getPoint();
for (SceneShape s : shapes)
{
if (s.contains(mousePoint))
s.setSelected(!s.isSelected());
}
repaint();
}
});
addMouseMotionListener(new
MouseMotionAdapter()
{
public void mouseDragged(MouseEvent event)
{
Point lastMousePoint = mousePoint;
mousePoint = event.getPoint();
for (SceneShape s : shapes)
{
if (s.isSelected())
{
double dx
= mousePoint.getX() - lastMousePoint.getX();
double dy
= mousePoint.getY() - lastMousePoint.getY();
s.translate((int) dx, (int) dy);
}
}
repaint();
}
});
Can someone help explain to me what is causing the program to deselect an already selected image when I drag it instead of moving it and how to fix this problem? Thanks.
One of the side effects of a drag operation is the fact that mouseClicked
won't be called. Why is this important? Basically you can use this fact to make a decision about whether a object should be deselected or not within the mouseClicked
event instead of something like mousePressed
or mouseReleased
.
It does require you to maintain some information about the current and previous states, so you know whether the object was just selected or was previously selected, but the basic idea works well.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class WhatADrag {
public static void main(String[] args) {
new WhatADrag();
}
public WhatADrag() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private List<Rectangle> boxes;
private Rectangle selected;
public TestPane() {
boxes = new ArrayList<>(25);
int x = 0;
int y = 0;
for (int index = 0; index < 10; index++) {
boxes.add(new Rectangle(x, y, 100, 100));
x += 25;
y += 25;
}
MouseAdapter ma = new MouseAdapter() {
private Rectangle previous;
private Point delta;
@Override
public void mousePressed(MouseEvent e) {
List<Rectangle> reversed = new ArrayList<>(boxes);
Collections.reverse(reversed);
previous = selected;
if (selected == null || !selected.contains(e.getPoint())) {
for (Rectangle box : reversed) {
if (box.contains(e.getPoint())) {
selected = box;
delta = new Point(e.getX() - selected.x, e.getY() - selected.y);
repaint();
break;
}
}
if (selected != null) {
boxes.remove(selected);
boxes.add(boxes.size() - 1, selected);
}
} else if (selected != null) {
delta = new Point(e.getX() - selected.x, e.getY() - selected.y);
}
}
@Override
public void mouseClicked(MouseEvent e) {
if (selected == previous && selected != null && selected.contains(e.getPoint())) {
selected = null;
repaint();
}
}
@Override
public void mouseDragged(MouseEvent e) {
if (selected != null) {
int x = e.getX() - delta.x;
int y = e.getY() - delta.y;
selected.x = x;
selected.y = y;
repaint();
}
}
};
addMouseListener(ma);
addMouseMotionListener(ma);
}
@Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
for (Rectangle box : boxes) {
if (box != selected) {
g2d.setColor(Color.BLUE);
g2d.fill(box);
g2d.setColor(Color.BLACK);
g2d.draw(box);
}
}
if (selected != null) {
g2d.setColor(Color.CYAN);
g2d.fill(selected);
g2d.setColor(Color.BLUE);
g2d.draw(selected);
}
g2d.dispose();
}
}
}
I am just so lost. I am looking at all this code and don't even understand what it is doing.
Yeah, I feel like this about my code a lot.
Basically...
First: mousePressed
is called, I reverse my list of objects, because the top most component will be the last in the list (this is my requirement), I store the currently selected object in the previous
variable, I use this to determine if there has been a change in selection or not. I check to see if the user clicked the selected
object or not, if they did, we can basically skip every thing else. If not, we determine what they clicked, if anything. The delta
is simply the difference between the place they clicked and the location of the object, this is used to make the drag more natural
If no drag occurs: mouseClicked
is called. We test to see if the selected
object is equal to the previous
object and if the mouse was clicked within the selected
object, if these are true
, then the currently selected
object should be deselected. Otherwise the user has basically just changed the selection, so we don't want to immediately deselect it.
Else if a drag occurs: mouseDragged
is called. We simply check to see if something is selected
, we calculate the difference between the current mouse position and the "click offset" and update the position of the selected
object
Clear as mud :P
One thing to also remember is mouseReleased
will always be called after mousePressed
, even if mouseClicked
isn't (which is called after mouseReleased
when no dragging occurs).