Hi,

I'm writing code for a graphical map of a shopping center. Whilst writing the code I realised it would be simpler to be able to draw objects using "names" instead of values. E.g. g.drawRect(Asda); instead of g.drawRect(100,100,40,40);. Is this possible? I have tried writing various classes but I can't get the program to work. Also when I click on the map I would like the program to state the nearest object to the mouse click. So far I have managed to make the program tell me the name of the object I have clicked on. Again help with this would be much appreciated. The code is below and I have uploaded the java files so you can test to see what they do. I use a separate java file to run this program.

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.text.*;
public class graphicalMap

 extends JFrame implements MouseListener {
	int xsize=700, ysize=700; //JFrame size values
	int x,y; //Used to draw small circle
	String message; //Used to write message when user clicks
	
	public graphicalMap() {
		setSize(xsize, ysize); //Set JFrame size
		setVisible(true); //Set visiility to true
		show(); //Show
		addMouseListener(this); //Add mouse listener events
	}
	
	public void mouseClicked(MouseEvent e)
	{
	x=e.getX(); //Get x co-ordinate from mouse click
	y=e.getY(); //Get y co-ordinate from mouse click
		
		if( ((x-50 > 0) && (x-50 < 40)) && ((y-50 > 0) && (y-50 < 40)) ) { //If click is in Asda
	 		message = "Asda: The best place to shop";
		} else {
	 		if( ((x-50 > 0) && (x-50 < 40)) && ((y-100 > 0) && (y-100 < 40)) ) { //If click is in Tesco
	 			message = "Tesco: The second best place to shop";
			} else {
				if( ((x-500 > 0) && (x-500 < 40)) && ((y-50 > 0) && (y-50 < 40)) ) { //If click is in Morrisons
					message = "Morrisons: The third best place to shop";
				} else {
					if( ((x-500 > 0) && (x-500 < 40)) && ((y-100 > 0) && (y-100 < 40)) ) { //If click is in Sainsburys
						message = "Sainsburys: The fourth best place to shop";
					} else {
							message = "";
					}
				}
			}
		}
		
		repaint();
	}
	
	public void mouseExited(MouseEvent e) {}
	public void mouseEntered(MouseEvent e) {}
	public void mouseReleased(MouseEvent e) {}
	public void mousePressed(MouseEvent e) {}
	
	public void paint(Graphics g) {
		super.paint(g);
		
		//SHOPS
		g.setColor(Color.black);
		g.drawRect(50,50,40,40); //Asda
		g.drawRect(65,70,10,20); //Asda door
		
		g.drawRect(50,100,40,40); //Tesco
		g.drawRect(65,120,10,20); //Tesco door
		
		g.drawRect(500,50,40,40); //Morrisons
		g.drawRect(515,70,10,20); //Morrisons door
		
		g.drawRect(500,100,40,40); //Sainsburys
		g.drawRect(515,120,10,20); //Sainsburys door
		
		//SMALL CIRCLE (MOUSE CLICK)
		g.drawOval(x,y,3,3);
		
		//ROADS
		g.setColor(Color.blue);
		g.drawLine(90,63,500,63); //First road (Top)
		g.drawLine(90,77,150,77); //First road (Bottom before first intersection)
		g.drawLine(164,77,440,77); //First road (Bottom after first interesction)
		g.drawLine(454,77,500,77); //First road (Bottom after second intersection)
		
		g.drawLine(90,113,150,113); //Second road (Top before first intersection)
		g.drawLine(164,113,440,113); //Second road (Top after first intersection)
		g.drawLine(454,113,500,113); //Second road (Top after second intersection)
		g.drawLine(90,127,150,127); //Second road (Bottom before first intersection)
		g.drawLine(164,127,440,127); //Second road (Bottom after first intersection)
		g.drawLine(454,127,500,127); //Second road (Bottom after second intersection)
		
		g.drawLine(150,77,150,113); //Third road (Left before intersection)
		g.drawLine(150,127,150,500); //Third road (Left after intersection)
		g.drawLine(164,77,164,113); //Third road (Right before intersection)
		g.drawLine(164,127,164,486); //Third road (Right after intersection)
		
		g.drawLine(440,77,440,113); //Fourth road (Left before intersection)
		g.drawLine(440,127,440,486); //Fourth road (Left after intersection)
		g.drawLine(454,77,454,113); //Fourth road (Right before intersection)
		g.drawLine(454,127,454,500); //Fourth road (Right after intersection)
		
		g.drawLine(164,486,440,486); //Fifth road (Top)
		g.drawLine(150,500,454,500); //Fifth road (Bottom)
		
		//MESSAGE (MOUSE CLICK ON OBJECT)
		g.setColor(Color.red);
		g.drawString(message,40,40); //String drawn by mouse click on object
		
		
	}
}

Recommended Answers

All 32 Replies

Hi,

I'm writing code for a graphical map of a shopping center. Whilst writing the code I realised it would be simpler to be able to draw objects using "names" instead of values. E.g. g.drawRect(Asda); instead of g.drawRect(100,100,40,40);. Is this possible? I have tried writing various classes but I can't get the program to work. Also when I click on the map I would like the program to state the nearest object to the mouse click. So far I have managed to make the program tell me the name of the object I have clicked on. Again help with this would be much appreciated. The code is below and I have uploaded the java files so you can test to see what they do. I use a separate java file to run this program.

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.text.*;
public class graphicalMap
 
 extends JFrame implements MouseListener {
	int xsize=700, ysize=700; //JFrame size values
	int x,y; //Used to draw small circle
	String message; //Used to write message when user clicks
 
	public graphicalMap() {
		setSize(xsize, ysize); //Set JFrame size
		setVisible(true); //Set visiility to true
		show(); //Show
		addMouseListener(this); //Add mouse listener events
	}
 
	public void mouseClicked(MouseEvent e)
	{
	x=e.getX(); //Get x co-ordinate from mouse click
	y=e.getY(); //Get y co-ordinate from mouse click
 
		if( ((x-50 > 0) && (x-50 < 40)) && ((y-50 > 0) && (y-50 < 40)) ) { //If click is in Asda
	 		message = "Asda: The best place to shop";
		} else {
	 		if( ((x-50 > 0) && (x-50 < 40)) && ((y-100 > 0) && (y-100 < 40)) ) { //If click is in Tesco
	 			message = "Tesco: The second best place to shop";
			} else {
				if( ((x-500 > 0) && (x-500 < 40)) && ((y-50 > 0) && (y-50 < 40)) ) { //If click is in Morrisons
					message = "Morrisons: The third best place to shop";
				} else {
					if( ((x-500 > 0) && (x-500 < 40)) && ((y-100 > 0) && (y-100 < 40)) ) { //If click is in Sainsburys
						message = "Sainsburys: The fourth best place to shop";
					} else {
							message = "";
					}
				}
			}
		}
 
		repaint();
	}
 
	public void mouseExited(MouseEvent e) {}
	public void mouseEntered(MouseEvent e) {}
	public void mouseReleased(MouseEvent e) {}
	public void mousePressed(MouseEvent e) {}
 
	public void paint(Graphics g) {
		super.paint(g);
 
		//SHOPS
		g.setColor(Color.black);
		g.drawRect(50,50,40,40); //Asda
		g.drawRect(65,70,10,20); //Asda door
 
		g.drawRect(50,100,40,40); //Tesco
		g.drawRect(65,120,10,20); //Tesco door
 
		g.drawRect(500,50,40,40); //Morrisons
		g.drawRect(515,70,10,20); //Morrisons door
 
		g.drawRect(500,100,40,40); //Sainsburys
		g.drawRect(515,120,10,20); //Sainsburys door
 
		//SMALL CIRCLE (MOUSE CLICK)
		g.drawOval(x,y,3,3);
 
		//ROADS
		g.setColor(Color.blue);
		g.drawLine(90,63,500,63); //First road (Top)
		g.drawLine(90,77,150,77); //First road (Bottom before first intersection)
		g.drawLine(164,77,440,77); //First road (Bottom after first interesction)
		g.drawLine(454,77,500,77); //First road (Bottom after second intersection)
 
		g.drawLine(90,113,150,113); //Second road (Top before first intersection)
		g.drawLine(164,113,440,113); //Second road (Top after first intersection)
		g.drawLine(454,113,500,113); //Second road (Top after second intersection)
		g.drawLine(90,127,150,127); //Second road (Bottom before first intersection)
		g.drawLine(164,127,440,127); //Second road (Bottom after first intersection)
		g.drawLine(454,127,500,127); //Second road (Bottom after second intersection)
 
		g.drawLine(150,77,150,113); //Third road (Left before intersection)
		g.drawLine(150,127,150,500); //Third road (Left after intersection)
		g.drawLine(164,77,164,113); //Third road (Right before intersection)
		g.drawLine(164,127,164,486); //Third road (Right after intersection)
 
		g.drawLine(440,77,440,113); //Fourth road (Left before intersection)
		g.drawLine(440,127,440,486); //Fourth road (Left after intersection)
		g.drawLine(454,77,454,113); //Fourth road (Right before intersection)
		g.drawLine(454,127,454,500); //Fourth road (Right after intersection)
 
		g.drawLine(164,486,440,486); //Fifth road (Top)
		g.drawLine(150,500,454,500); //Fifth road (Bottom)
 
		//MESSAGE (MOUSE CLICK ON OBJECT)
		g.setColor(Color.red);
		g.drawString(message,40,40); //String drawn by mouse click on object
 
 
	}
}

You can catapult this to a higher level by creating a class for the stores and their coordinates - something like:

class Store {
  String name;
  int x, y, width, height;
  int doorX. (etc)

Pass all the coords to the constructor.
Then have methods in the class like

public void drawStore(Graphics g) {
  // do the drawrects for this store and its door  here
}
public boolean isClicked(int x, int y) {
  // compare these coords with the stores coords, return true if inside
}

In the main program create an array of Stores, initialised with 3 new Stores (names, coordinates etc.
Now the code in you main routine collapses down to simple loops like

Store clickedStore= null;
for (int i = 0; i < Stores.length; i++) {
   if (Stores[i].isClicked(e.getX(), e.getY()) {
      clickedStore = Stores[i];
      break;
   }
}
...
public void paint(Graphics g) {
  super.paint(g);
  for (int i = 0; i < Stores.length; i++) {
    Stores[i].drawStore(g);
  }
  ...

For closest store you could do a variant on isClicked(...) to return how far the x,y coords are from the center of the door of the store. You can then use these in a simple loop to find which Store is closest.

It's a bit of an up-front effort, but it pays huge dividends as the app gets bigger & more complex. It's also the "right" object-oriented Java way to do things.

Thank you for your help, I'll implement your ideas when I get home and see what happens. I'm a newbie to java programming so would it be possible for you to give me an idea of how to return how far the coords are? And the loop needed to test the distance from the mouseclick. I really appreciate your help, you've taught me a lot from your current help

The distance between two points? Pythagoras!
double distance = Math.sqrt((x1-x2)^2 + (y1-y2)^2)
although there's a neat method in the Math class to handle some of the snags that this can cause in extreme cases:
double distance = Math.hypot((x1-x2), (y1-y2)); // that's hypot an in hypotenuse!

In your case the x1,y1 are the coords of the store (maybe use the center of the door?) and x2,y2 the coordinates on the mouse click (or vice-versa - it's the same answer).

Given that method, the closest will follow a very standard pattern, something like:

Store closestStore= null;
double closestDistance = 99999;
for (int i = 0; i < Stores.length; i++) {
  double dist = Stores[i].distanceTo(e.getX(), e.getY())
  if (dist < closestDistance  ) {
    closestStore= Stores[i];
    closestDistance = dist;
  }
}

Hi,

you can use java.awt.Rectangle, however I don't think you can draw these directly using drawRect(). But you can use the x, y, width and height of your rectangles and draw. By using rectangles you can ask each rectangle if they contain a point (mouse x and y for instance).

myRect.contains(mouseX, mouseY);

In case you want to move all rectangles just change the bounds of the rectangle, you don't need to bother about the bound-checking.

You can probably use Polygons instead of Rectangles if you like. Polygons can be drawn using drawPolygon(polygon).

About the distance, you can get the distance between two Points by

Point p1, p2;
int distance;
p1 = new Point(0,0);
p2 = new Point(10, 10);
distance = p1.distance(p2);

You can get the centerX and centerY of any Rectangle, so if you create a Point using the center of the rectangle and a Point from the mouse position then you can get the distance to all the shops. Then just compare the distances (if you just clicked a shop, this shop will always be the closest, so keep track of your current shop).

Again thank you for you help, my program won't accept me adding the new classes for the stores and I'm struggling to understand everything now.

Could you add the changes to my code so that it has all of the classes and arrays necessary so that I can understand from there how it works? And also the Pythagorus theory you gave me tells me the distance is off the JFrame which is strange as I gave the values of x1 = 70 and y1 = 70 which is in the middle of the Asda store.

I used this to try and find the closest but for some reason it constantly says either asda or tesco are closest and the coordinates repeat from the bottom of the JFrame as well.

double asdaDist = Math.sqrt((70*x)^2 + (70*y)^2);
		double morrisonsDist = Math.sqrt((520*x)^2 + (70*y)^2);
		double sainsburysDist = Math.sqrt((520*x)^2 + (120*y)^2);
		double tescoDist = Math.sqrt((70*x)^2 + (120*y)^2);
		
		if(asdaDist < tescoDist && asdaDist < morrisonsDist && asdaDist < sainsburysDist) {
			message = "Asda is closest";
		} else {
			if(tescoDist < asdaDist && tescoDist < morrisonsDist && tescoDist < sainsburysDist) {
				message = "Tesco is closest";
			} else {
				if(morrisonsDist < asdaDist && morrisonsDist < tescoDist && morrisonsDist < sainsburysDist) {
					message = "Morrisons is closest";
				} else {
					if(sainsburysDist < asdaDist && sainsburysDist < morrisonsDist && sainsburysDist < tescoDist) {
						message = "Sainsburys is closest";
				}
			}
		}
	}

I used x1 as and y1 as the coordinates in the middle of the rectangle

I've managed to get the distance working but I can't figure out how to use your way of creating a class for the stores, using the methods and constructors and then the simple loops. If possible could you code a similar sort of thing to my program so that I can look at what you've done and figure out what you've done and why. I would appreciate it greatly.

I'm sorry about asking so many question! I've made the class and methods work now.
However I have one problem left.
With your loop to display if I click on a store, how do you display the store that is clicked as a string so I can use it in g.drawString(). At the minute it doesn't display anything. Thanks in advance!

how do you display the store that is clicked as a string

Store clickedStore= null;
for (int i = 0; i < Stores.length; i++) {
   if (Stores[i].isClicked(e.getX(), e.getY()) {
      clickedStore = Stores[i];
      break;
   }
}
String storeName = clickedStore.getName();

... or have I misunderstood your question?

Thank you this allowed me to display the result as a string!

New problem now! It only displays the first store in the arrays name now :( I'm sure we'll get there in the end.

I'm sure we'll get there in the end.

I'm sure we will.
And in the process you are getting a really good grounding in good Java practice.

As for the current problem - use lots of print statements to confirm exactly what code is being executed and what data values are being calculated and stored. Debugging by just looking at the code is a fool's game.

Can you see the problem in my code?

public boolean isClicked(int a, int b, int c, int d) {
		if( ((a-x > 0) && (a-x < c)) && ((b-y > 0) && (b-y < d)) ) {
			return true;
			}
			return true;
		}
		
	public String getName() {
		return name;
}

...

public void mouseClicked(MouseEvent e) {
	x=e.getX();
	y=e.getY();
		store clickedStore = null;
			for (int i = 0; i < stores.length; i++) {
			if (stores[i].isClicked(e.getX(), e.getY(),x,y)) {
				clickedStore = stores[i];
				break;	
			}
		}
		storeName = clickedStore.getName();
		
		
	repaint();
	}

My java has become much better from your help. And thank you! I understand a lot more now.

My full code now looks like this...

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.text.*;
import java.util.*;

public class maptest extends JFrame implements MouseListener {
	
	int xsize=700, ysize=700,x,y;
	String storeName;
	
	public maptest() {
		setSize(xsize, ysize); //Set JFrame size
		setVisible(true); //Set visiility to true
		show(); //Show
		addMouseListener(this); //Add mouse listener events
	}
	
	class store{
		String name;
		int x, y, width, height, centerX, centerY;
	
		public store(String storeName,int storeX,int storeY, int storeWidth, 
					 int storeHeight, int storeCenterX,int storeCenterY) {
			name = storeName;
			x = storeX;
			y = storeY;
			width = storeWidth;
			height = storeHeight;
			centerX = storeCenterX;
			centerY = storeCenterY;
		}
	
		public void drawStore(Graphics g) {
			g.drawRect(x,y,width,height);
		}
		public boolean isClicked(int a, int b, int c, int d) {
			if( ((a-x > 0) && (a-x < c)) && ((b-y > 0) && (b-y < d)) ) {
				return true;
			}
			return true;
		}
		
		public String getName() {
			return name;
		}
		
	}	
	
	store Asda = new store("Asda",50,50,40,40,70,70);
	store Tesco = new store("Tesco",50,100,40,40,70,120);
	store Morrisons = new store("Morrisons",500,50,40,40,520,70);
	store Sainsburys = new store("Sainsburys",500,100,40,40,520,120);
	
	store[] stores = {Asda,Tesco,Morrisons,Sainsburys};	
	
	class road{
		int x1,x2,y1,y2;
		
		public road(int roadX1,int roadX2,int roadY1,int roadY2) {
			x1 = roadX1;
			x2 = roadX2;
			y1 = roadY1;
			y2 = roadY2;
		}
		
		public void drawRoad(Graphics g) {
			g.drawLine(x1,x2,y1,y2);
		}
	
	}
								
	road firstTop = new road(90,63,500,63);
	road firstBottom1 = new road(90,77,150,77);
	road firstBottom2 = new road(164,77,440,77);
	road firstBottom3 = new road(454,77,500,77);
	road secondTop1 = new road(90,113,150,113);
	road secondTop2 = new road(164,113,440,113);
	road secondTop3 = new road(454,113,500,113);
	road secondBottom1 = new road(90,127,150,127);
	road secondBottom2 = new road(164,127,440,127);
	road secondBottom3 = new road(454,127,500,127);
	road thirdLeft1 = new road(150,77,150,113);
	road thirdLeft2 = new road(150,127,150,500);
	road thirdRight1 = new road(164,77,164,113);
	road thirdRight2 = new road(164,127,164,486);		
	road fourthLeft1 = new road(440,77,440,113);
	road fourthLeft2 = new road(440,127,440,486);
	road fourthRight1 = new road(454,77,454,113);
	road fourthRight2 = new road(454,127,454,500);
	road fifthTop = new road(164,486,440,486);
	road fifthBottom = new road(150,500,454,500);
	
	road[] roads = {firstTop,firstBottom1,firstBottom2,firstBottom3,
					secondTop1,secondTop2,secondTop3,secondBottom1,secondBottom2,secondBottom3,
					thirdLeft1,thirdLeft2,thirdRight1,thirdRight2,
					fourthLeft1,fourthLeft2,fourthRight1,fourthRight2,
					fifthTop,fifthBottom};

		
	public void mouseClicked(MouseEvent e) {
	x=e.getX();
	y=e.getY();
		store clickedStore = null;
			for (int i = 0; i < stores.length; i++) {
			if (stores[i].isClicked(e.getX(), e.getY(),x,y)) {
				clickedStore = stores[i];
				break;	
			}
		}
		storeName = clickedStore.getName();
		
		
	repaint();
	}
	
	public void mouseExited(MouseEvent e) {}
	public void mouseEntered(MouseEvent e) {}
	public void mouseReleased(MouseEvent e) {}
	public void mousePressed(MouseEvent e) {}
	
	public void paint(Graphics g) {
		super.paint(g);
		
		
		g.drawOval(x,y,3,3);
		for (int i = 0; i< stores.length; i++) {
			stores[i].drawStore(g);
		}
		g.setColor(Color.blue);
		for (int i = 0; i< roads.length; i++) {
			roads[i].drawRoad(g);
			
		}
		g.drawString(storeName,400,400);
	}
	
}

I can't work out the problem for the life of me.

I was really happy to see the Line class - you've obviously "got" the important idea here!
What are the parameters c and d in isClicked? I would expect to see just the x,y of the click as parameters, and for the method to use the Stores's x,y,width.height.
(If parameter names aren't self-explanatory then (1) they should be and (2) a quick explanatory comment is essential.)

What exactly is the current problem - do you get an exception, unexpected results etc?
Please describe the problem precisely.

Ignore the c and d, I wad just trying something out. And yes the idea of using classes to do thing is much more efficient.

The exact problem is that when I click on any of the stores the variable clickedStore only stores the value in stores[0] which when In use getName displays asda as the store I've clicked in.

Although I was thinking that c and d should store the width and height of the store? This would make sense to do. However even when I implement this change, the above problem still occurs.

Ah I see what you mean about using the stores x,y,width and height in the method. I'll try this and see what happens.

Maybe a logic error in isClicked? print the params, and values in the loop, to check it out.

Sorry, I only saw the 1st page of this thread. Please ignore my previous post.

FOUND IT!

public boolean isClicked(int a, int b) {
		if( ((a-x > 0) && (a-x < width)) && ((b-y > 0) && (b-y < height)) ) {
		return true;
		} 
		return true;
		}

This was returning true for everything. It needed to be...

public boolean isClicked(int a, int b) {
			if( ((a-x > 0) && (a-x < width)) && ((b-y > 0) && (b-y < height)) ) {
			return true;
			} else {
			return false;
			}
		}

Which returns false if the store isn't clicked and then allows the loop to progress! :D

Thank you again for your help!

I guess we all should have noticed that one!
ps your code is a long version of

public boolean isClicked(int a, int b) {
   return (a >= x) && (a <= x+width) && (b >= y) && (b <= y+height);
}

(I also rearranged the tests to make it clearer what they were doing, and to include clicks right on the boundary line)

Thank you again! That piece of code is much more efficient.

New question... is it possible to compare the values of objects in arrays against each other.

For example if I had objects that looked like this:

store Asda = new store("Asda",50,50,40,40,70,70,0,0,0)
store Tesco = new store("Tesco",50,100,40,40,70,120,0,0,0);
store Morrisons = new store("Morrisons",500,50,40,40,520,70,0,0,0);
store Sainsburys = new store("Sainsburys",500,100,40,40,520,120,0,0,0);

The three 0's are calculated through the program to work out the distance between the center of the store and the coordinates of the mouse click. So each time I click the mouse these values change.

For example: say the center of the store asda is at x-70 and y-70 and I click at x-100 and y-100 the new store code would look like this.

store Asda = new store("Asda",50,50,40,40,70,70,30,30,60

The first 30 being the difference between the xcoord of the store center the xcoord of the mouse click, the second 30 being the difference between the ycoord of the store center and the y coord of the mouse click and the 60 being both the differences added together to give the total distance from the mouse click.

So now I would like to compare the total differences of each store against each other and then display the store which has the smallest distance. How can I do this?

There is no need to keep the "distance to" values in your "store" class. Those can be computed on the fly from your mouse locations.

You can create a separate method distanceFrom() that computes the distance from a point to a store. It could be on the store class as distanceFrom(int x, int y) or you could put it on the map class as distanceFrom(store s, int x, int y) You could also switch to using java.awt.Point class instead of the x,y pairs if you wish.

If I had various stores how would it store each value and then compare each value and then relate it back to the store so I can display the closest store?

You have to recalculate those values each time the mouse reference position is moved, but there really isn't any reason to keep them after you have determined which store is nearest is there?

So when the mouse location changes, loop the stores to determine the distance to each (using the method I mentioned) and keep track of the closest as you loop. You can maintain a 'nearestStore' reference in your map test if you need to refer back to it for repaints or such.

I'm sorry, I'm struggling to follow what you mean. I'm storing them because I will be clicking various times and then each value will recalculate each time I click. Then I could use a loop to compare these values each time. I just can't figure out how to compare the vales of the objects in the array.

So in pseudo-code, each time you click you just need

for each store in stores{
  float distance = store.distanceFrom( mousePoint)
  if distance < minDistance {
    minDistance = distance
    nearestStore = store
  }
}

I don't see any reason why you would need or want to store the distance to the mouse in the object itself, since it's just a transient reference point. What you really are interested in is which store is closest. Determining that doesn't require putting the mouse coordinated into your store data class.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.