2D arraylist to keep a point - java

i made a program that whenever i click my mouse, it draws a circle in the point that i clicked,
now i want it to check if there is already a circle in the point that i am clicking , and if there is then i want to delete that circle.
i thought to do it with a 2D arralist that will keep all the points already taken, can anyone show me how do i do it?
this is my code so far:
public class delta extends Applet implements MouseListener {
private Graphics globalg;
public void init(){
this.addMouseListener(this);
}
public void paint(Graphics g){
this.setSize(new Dimension (1000, 1000));
globalg = g.create();
}
public void draw(int x, int y , int width , int height){
globalg.setColor(getColor());
Ellipse2D circle = new Ellipse2D.Double((double) x , (double) y ,(double) width , (double) height);
Graphics2D g2 = (Graphics2D) globalg;
g2.fill(circle);
}
public Color getColor(){
int r = (int) (Math.random() * 256);
int g = (int) (Math.random() * 256);
int b = (int) (Math.random() * 256);
return new Color(r , g ,b);
}
#Override
public void mouseClicked(MouseEvent e) {
int x = e.getX();
int y = e.getY();
draw(x , y , 20 , 20);
}
#Override
public void mousePressed(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
}

I won't be telling you exactly what to do, but I'll get you in the right direction.
Step one - Your Data Structure
Now, I can see why you wanted to use a nested ArrayList for this, but conceptually this isn't very nice. You can represent a matrix of values without a complex data structure by enclosing the relevant values inside an Object. Now, you could make your own object or you can use the Java Point class. For the purposes of this, we'll make your own object so you can easily add your own values (colour, size, etc).
public class MyCircle {
}
And in there, you can store your x and y positions. These can then be stored into a List, so your MyCircle objects will be accessed via something like:
private List<MyCircle> circles;
Step Two - Handling Mouse Clicks
You've already implemented the MouseListener interface, so we're in a good place to get building on that. Now, the way I see it, there are two possibilities that you need to account for when handling a mouse click.
No Circle exists and you need to draw one.
A Circle exists and you need to delete it.
No Circle Exists
If no circle exists, then you draw it. You seem to have got this bit handled so there's no sense explaining it.
A Circle Exists
This is where you've stopped. So, first things first, you'll need to traverse your data structure, which we've named circles..
for(MyCircle circle : circles) {
}
Now, I'll assume you've got something like x and y in here, a long with the relevant accessors and mutators. You then can check the co-ordinates..
if(circle.getX() == x && circle.getY() == y) {
// A circle was put at this point..
}
NOTE: This will make it quite hard to delete a circle. What you really want is to be able to check if the use has clicked inside a circle! How do you do this? Well, that's about comparing the values. You want to make sure that the user clicked at an x value that is larger than the x value of the circle, but smaller than x + width of the circle. Likewise, you want to make sure the user also clicked at a y value that is larger than the y value of the circle, but smaller than y + width of the circle.
if(x > circle.getX() && x < (circle.getX() + circle.getWidth())) {
// This was a click inside the circle on the X axis. Your turn to check the y!
}

Related

MousePressed and mouseReleased to create objects

I have a ball class that creates a ball object. I want to created a ball object when the mouse is pressed, if the mouse is pressed and held the ball should follow the mouse(while the mouse is pressed). When the mouse is releases, the ball should stay at the current mouseX and mouseY, and no longer follow the mouse.
When the mouse is pressed again, another ball object is created and does the same as the first object and so on...A new ball object is created every time the mouse is pressed.
I have some code that creates an object, it follows the mouse and it puts on the canvas when I release the mouse. But if i press my mouse again the original ball goes back to the mouse. How do I "disengage" the ball object so i can make more ball objects that doesnt effect the position of the previously placed balls?.
I plan to use ArrayLists to make many objects .
class Ball {
float xPos, yPos;
Ball(float xPos, float yPos) {
this.xPos= xPos;
this. yPos= yPos;
}
void drawBall() {
ellipse(xPos, yPos, 50, 50);
println("X" + xPos + " Y:"+ yPos);
}
}
Ball ball1;
Ball ball2;
ArrayList<Ball> ballList = new ArrayList<Ball>();
void setup() {
size(600, 600);
ball1=new Ball(900, 900);
ball2=new Ball(900, 900);
}
void draw() {
background(150);
if (mousePressed ) {
ball1.xPos= mouseX;
ball1.yPos=mouseY;
}
ball1.drawBall();
}
The issue here are that you're not managing the array at all, and instead are working with the same object all the time. I re-wrote your example using the arraylist to store the Ball objects, and also to create new balls when the user clicks a mouse button.
Please note here that I'm deliberately using the "last item added to the arraylist" instead of creating an object which would be a reference to the this object. This is because I don't want to confuse you with references and such.
ArrayList<Ball> ballList = new ArrayList<Ball>();
void setup() {
size(600, 600);
}
void draw() {
background(150);
// if the mouse button is held down, set the ball's coordinates to the mouse coordinates
if (ballList.size() > 0 && mousePressed) {
ballList.get(ballList.size() - 1).xPos = mouseX; // 'ballList.get(ballList.size() - 1)' is the java way to get the last item added to an arrayList
ballList.get(ballList.size() - 1).yPos = mouseY;
}
// draw every ball in the array (the weird format is just shorthand for a "for each" loop)
for(Ball b : ballList) {
b.drawBall();
}
}
// this method will trigger once every time the user press a mouse button
void mousePressed() {
ballList.add(new Ball(mouseX, mouseY));
}
class Ball {
float xPos, yPos;
Ball(float xPos, float yPos) {
this.xPos= xPos;
this.yPos= yPos;
}
void drawBall() {
ellipse(xPos, yPos, 50, 50);
}
}
By targeting the last created ball instead of a specific ball, you ensure that you're always using the right object. Also, notice how I just let the ball objects draw themselves in a loop. The 'for each' form ensure that whatever number of balls there currently is in the arrayList, they will all be printed anyway.
Good luck with this project and if something is confusing about my answer don't hesitate to reach out and ask questions about it.
Have fun!

How to properly "layer" images (and changing the source) without inheriting from Swing

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);
}
}
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:
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
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.

Creating and storing a varying number of shapes in an arraylist in javafx

I have been messing around with javafx for practice and ran across something I couldn't figure out. I want to put a varying number of rectangles into an arraylist. Right now, instead of that, I am storing each rectangle as an double array (double[]) of the various properties, then setting a base rectangle to those values and returning that.
public class example{
Rectangle myRectangle = new Rectangle(0,0,25,25);
ArrayList<double[]> rectangles = new ArrayList();
double[] tempArray = [0,0];
public void addRect (double x, double y){
this.tempArray[0] = x;
this.tempArray[1] = y;
this.rectangles.add(this.tempArray);
};
public Rectangle getRect (int id){
this.myRectangle.setX(this.rectangles.get(id)[0]);
this.myRectangle.setY(this.rectangles.get(id)[1]);
return(this.rectangle);
};
}
In this example, when I call getRect, it sets the x and y of the base rect, then returns that rect. This works, but I am wondering if there is a way to store multiple instances of Rectangle in the ArrayList. The main issue I saw doing this is the fact that you have to name the instance(in the example above, myRectangle). I imagine that if there is a way around this issue, it would be to name the instance based on a string, in other words:
Rectangle "myRectangle" = new Rectangle();
which is not possible, as far as I know.
I am fairly new to Javafx and Java in general so if there is anything else off with my code feel free to correct that. Thanks!
You just need to make an ArrayList<Rectangle> and add rectangles to it.
public class Example {
private List<Rectangle> rectangles = new ArrayList<>();
public void addRectangle(double x, double y, double width, double height) {
rectangles.add(new Rectangle(x, y, width, height));
}
public Rectangle getRectangle(int index) {
return rectangles.get(index);
}
}
You should note that your original code really doesn't work as expected at all. For example, try:
// please do NOT name classes with lower case...
example e = new example();
e.addRectangle(0, 0);
e.addRectangle(100, 100);
Rectangle rect1 = e.getRectangle(0);
System.out.println("Rectangle 1: ["+rect1.getX()+", "+rect1.getY()+"]");
Rectangle rect2 = e.getRectangle(1);
System.out.println("Rectangle 2: ["+rect2.getX()+", "+rect2.getY()+"]");
// but:
System.out.println("Rectangle 1: ["+rect1.getX()+", "+rect1.getY()+"]");
// oops.
System.out.println("Rectangle 1 and 2 are the same: " + (rect1==rect2) );

Exact Positioning When using Drag and Drop in GUI

I'm trying to implement a drag and drop functionality for a GUI I'm creating using WindowBuilder/ SWT Designer. At present, in order to determine where exactly on the canvas the drop takes place, I use
canvas.addPaintListener(new PaintListener() {
public void paintControl(PaintEvent e) {
int x = event.x - shell.getBounds().x - canvas.getBounds().x;
int y = event.y - shell.getBounds().y - canvas.getBounds().y;
e.gc.drawString(d, x, y);
}
});
But this is not an exact positioning at the mouse drop, instead it is very much further towards the right. How can I fix this? Thanks.
All you need is the very helpful function Control#toControl(int, int):
Returns a point which is the result of converting the argument, which is specified in display relative coordinates, to coordinates relative to the receiver.
canvas.addPaintListener(new PaintListener()
{
public void paintControl(PaintEvent e)
{
Point point = canvas.toControl(event.x, event.y);
e.gc.drawString(d, point.x, point.y);
}
});
That'll do it.

User-selected marker in time series data in Java

My code plots 5000 points of time series data in a panel that is 581 pixels wide by default, but this width changes when the user resizes the window. My code also plots several rectangular markers that each identify a local maximum/peak in this same space.
I need to enable the user to right click on any of the rectangular-peak-markers so that the user can manually delete any false peak. The problem is that my code is reporting different x-coordinates than expected when the user right-clicks on a peak-marker. I suspect that the reason may have to do with rounding error in converting from 581 x-pixels back to 5000 data indices. But I am not certain of the reason.
Can anyone suggest a solution that enables my users to manually select one of the above-described peak markers by right-clicking on it?
I am enclosing relevant sections of the code below. My actual code is very, very long, and too complicated to post. But the relevant portions below should be enough for someone to see the logic of my approach, and to then suggest a more effective approach.
The code that declares the class in question is:
class SineDraw extends JPanel implements MouseMotionListener, MouseListener {
// lots of code, including the two segments excerpted below
}
This segment of code overloads the paintComponent of the JPanel so that my data is plotted:
// declare some variables
ArrayList<Double> PeakList = new ArrayList<Double>() // this ArrayList is populated by an extraneous process
visiblePoints = 5000
hstep = getWidth()/visiblePoints //=581/5000 by default, but will change when user resizes window
int numPeaks = PeakList.size();
// scale (y-coordinate) data relative to height of panel
pts = new double[visiblePoints]
for (int i = 0; i < pts.length-1; i++){pts[i]=//data vertical scaled to fill panel;}
// plot the 5000 time-series-data-points within the 581 pixels in x-axis
for (int i = 1; i < visiblePoints; i++) {
int x1 = (int) ((i - 1) * hstep);
int x2 = (int) (i * hstep);
int y1 = (int)pts[i - 1];
int y2 = (int)pts[i];
g2.drawLine(x1, y1, x2, y2);
}
// plot a rectangle for each of the local peaks
for(int m=0;m<=(numPeaks-1);m++){
if(i==(int)(PeakList.get(m)){
int currentVal = (int)pts[(int)(PeakList.get(m)];
g2.drawRect((int)(PeakList.get(m), currentVal, 6, 6);
}
}
This section of code is for handling the right-clicking of the mouse:
public void mousePressed(MouseEvent e){
// check to see if right mouse button was clicked
boolean jones = (e.getModifiers()&InputEvent.BUTTON3_MASK)==InputEvent.BUTTON3_MASK;
if(jones==true){
// test the value returned as x-coordinate when user right-clicks (code always underestimates x-coordinate of local peaks by this test)
double ReverseHstep = visiblePoints/getWidth();
int getX_ConvertedTo_i = (int) (e.getX()*ReverseHstep);
System.out.println("getX_ConvertedTo_i is: "+getX_ConvertedTo_i );
// check to see if peaklist contains a value within the x-coordinates of the user-selected-rectangle
if(PeakList.contains((double)(e.getX()-3))
||PeakList.contains((double)(e.getX()-2))
||PeakList.contains((double)(e.getX()-1))
||PeakList.contains((double)(e.getX()))
||PeakList.contains((double)(e.getX()+1))
||PeakList.contains((double)(e.getX()+2))
||PeakList.contains((double)(e.getX()+3))
){
// handling code will go here, but for now it is a print test that never succeeds because x-coordinate is always underestimated
System.out.println("You just selected a peak!");
}
}
repaint();
}
I suggest you create objects (in this case Rectangles) for each thing you want to be clickable. Here is an over-simplified example of how you can make something you draw clickable. The key thing to take away from this is the mouseClicked method which will display a dialog only if the mouse clicked within the rectangle.
One tricky point is that I wasn't able to figure out how to make the rectangle filled in with color without drawing another rectangle over it. I'll leave that one for you ;-)
public class Canvas extends JPanel implements MouseListener{
private Rectangle rect = new Rectangle(100,100);
public Canvas(){
this.addMouseListener(this);
rect.setSize(100, 100);
}
#Override
public void paintComponent(Graphics g){
g.setClip(rect);
g.setColor(Color.RED);
g.fillRect(0, 0, 100, 100);
}
#Override
public void mouseClicked(MouseEvent e){
if(rect.contains(e.getPoint())){
JOptionPane.showConfirmDialog(this, "Click!");
}
}
// The rest of the MouseListener methods have been cut out
public static void main(String[] a){
JFrame frame = new JFrame("Canvas Thingy");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setBounds(0, 0, 300, 300);
frame.add(new Canvas());
frame.setVisible(true);
}
}

Categories