In JPanel zeichnen

  • Themenstarter Themenstarter dao1202
  • Beginndatum Beginndatum
D

dao1202

Gast
Hallo ihr 🙂 nicht erschrecken das wird jetz etwas lang... also ich soll per buttondruck ein rechteck im 8x8 pixel format zeichnen können es wieder löschen sowie ein start und endpunkt einfügen können... mein problem ist ich bekomme einen nullpointer denke es liegt daran das ich evtl nicht initialisiert habe !? und wenn wie kann ich das ändern??? hier der code

das ist die aufgabe
Es soll mit Java Swing ein Programm geschrieben werden, das den kürzesten Weg (im Sinne der Manhattan-Distanz) zwischen zwei Punkten grafisch darstellt. Der Nutzer soll dabei Start- und Endpunkt (je einer) festlegen sowie beliebig viele Hindernisse zeichnen können (Vergleich Stift-Werkzeug aus Microsoft Paint). Die Größe einer "Zelle" des Feldes soll 8x8 Pixel betragen. Das Auswählen der drei Werkzeuge "Startpunkt", "Endpunkt" und "Hindernis" soll über eine Toolbar geschehen.

Der angezeigte Weg soll nach jeder Änderung (Setzen von Start- oder Endpunkt sowie Zeichnen von Hindernissen) automatisch neu berechnet und visualisiert werden. Überlegt euch bei der grafischen Umsetzung, wie die Start- und Endpunkte visuell von Hindernissen unterscheidbar gemacht werden können. Der A*-Algorithmus zur Berechnung des Pfades und die Datenstruktur zum Speichern von Start- und Endpunkten sowie Hindernissen sind in der Vorgabe bereits enthalten, es muss lediglich der grafische Part (in der Klasse Main) programmiert werden.

graphnode.java
Java:
public class GraphNode implements Comparable<GraphNode>{
	private int x;
	private int y;
	private double fitness;
	private double distanceToPlayer = 99999999;
	
	private GraphNode home = null;
	private GraphNode north = null;
	private GraphNode south = null;
	private GraphNode west = null;
	private GraphNode east = null;
	
	public enum Type {EMPTY, START, END, PATH, OBSTACLE};
	
	public GraphNode(int x, int y) {
		this.x = x;
		this.y = y;
		calculateFitness();
	}
	
	/**
	 * Knoten zu Ausgangszustand
	 */
	public void reset(){
		home = null;
		distanceToPlayer = 99999999;
		calculateFitness();
	}
	
	/**
	 * @return oberer Nachbar
	 */
	public GraphNode getNorth() {
		return north;
	}

	/**
	 * setzt oberen Nachbar
	 * @param north oberer Nachbar
	 */
	public void setNorth(GraphNode north) {
		this.north = north;
	}

	/**
	 * @return unteren Nachbar
	 */
	public GraphNode getSouth() {
		return south;
	}

	/**
	 * setzt unteren Nachbar
	 * @param south unterer Nachbar
	 */
	public void setSouth(GraphNode south) {
		this.south = south;
	}

	/**
	 * @return linker Nachbar
	 */
	public GraphNode getWest() {
		return west;
	}

	/**
	 * setzt linken Nachbar
	 * @param west linker Nachbar
	 */
	public void setWest(GraphNode west) {
		this.west = west;
	}

	/**
	 * @return rechter Nachbar
	 */
	public GraphNode getEast() {
		return east;
	}

	/**
	 * setzt rechten Nachbar
	 * @param east rechter Nachbar
	 */
	public void setEast(GraphNode east) {
		this.east = east;
	}

	/**
	 * setzt Vorgänger auf dem bisherigen Pfad
	 * @param home Vorgänger
	 */
	public void setHome(GraphNode home){
		this.home = home;
	}
	
	/**
	 * @return den Vorgänger auf dem Pfad
	 */
	public GraphNode getHome() {
		return home;
	}
	
	/**
	 * berechnet momentane Wertigkeit
	 */
	public void calculateFitness(){			
		fitness = distanceToPlayer + estimateDistanceToTarget();
	}
	
	/**
	 * setzt die Entfernung zum Start
	 * @param distance
	 */
	public void setDistance(double distance){
		distanceToPlayer = distance;
	}

	/**
	 * @return die Entfernung zum Start
	 */
	public double getDistance(){
		return distanceToPlayer;
	}
	
	/**
	 * berechnet die Entfernung zum Start
	 */
	public void calculateDistance(){
		distanceToPlayer = 1 + home.distanceToPlayer;
	}
	
	/**
	 * @return die Wertigkeit
	 */
	public double getFitness(){
		return fitness;
	}
	
	/**
	 * prüft ob dieser Knoten die gegeben Parameter hat
	 * @param x Koordinate
	 * @param y Koordinate
	 * @return true wenn dieser Knoten mit den gegebenen Koordinaten übereinstimmt
	 */
	public boolean isNode(int x, int y) {
		if (this.x == x && this.y == y)
			return true;
		else
			return false;
	}
	
	/**
	 * @return x-Koordinate
	 */
	public int getX() {
		return x;
	}

	/**
	 * @return y-Koordinate
	 */
	public int getY() {
		return y;
	}
	
	/**
	 * schätzt die Entfernung zum Zielpunkt
	 * @return die Schätzung
	 */
	public double estimateDistanceToTarget() {
		int targetX = Map.getEnd().x;
		int targetY = Map.getEnd().y;
		
		return Math.sqrt((double) ((targetX-x)*(targetX-x) + (targetY-y)*(targetY-y)));
	}

	/**
	 * vergleicht anhand der Wertigkeit
	 */
	@Override
	public int compareTo(GraphNode node) {
		if (fitness == node.getFitness())
		return 0;
		else if (fitness > node.getFitness())
			return 1;
		else
			return -1;
	}
}


main.java
Java:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JToolBar;

/**
 * Hauptklasse, die vor allem fuer das Zeichnen der Elemente zustaendig ist.
 *
 */
public class Main {
	int lastX,lastY=0;
	final int OBSTACLE = 1;
	final int GOAL=2;
	final int START = 3;
	private int state = 0;
	private static final long serialVersionUID = 1L;
    private JToolBar toolbar;
	private JPanel drawPanel;

	/**
	 * Einmaliges initialisieren des Applets.
	 */
	public void init() {
		initValues();
		initToolbars();
		initDrawPanel();
		
		JPanel paneInIn = new JPanel(new BorderLayout());
		paneInIn.add(new JPanel(), BorderLayout.CENTER);
		paneInIn.add(this.drawPanel, BorderLayout.NORTH);
		
		JPanel paneIn = new JPanel(new BorderLayout());
		paneIn.add(paneInIn, BorderLayout.WEST);
		paneIn.add(new JPanel(), BorderLayout.CENTER);
		paneIn.add(new JPanel(), BorderLayout.SOUTH);
		JScrollPane pane = new JScrollPane(paneIn);
		pane.setPreferredSize(new Dimension(600,600));
		
		JPanel main = new JPanel(new BorderLayout());
		main.add(pane, BorderLayout.CENTER);
		
		JFrame mainFrame = new JFrame();
		mainFrame.setLayout(new BorderLayout());
		mainFrame.add(main, BorderLayout.CENTER);
		mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		mainFrame.pack();
		mainFrame.setVisible(true);
		mainFrame.add(toolbar,BorderLayout.NORTH);
	}
	
	/**
	 * Initialisiert das Panel, auf das die Map gezeichnet wird.
	 * Beinhaltet MouseListener zum Clicken und Draggen.
	 */
	private void initDrawPanel() {
		// TODO implementieren
		drawPanel = new JPanel() {
			@Override
			public void paint(Graphics g) {
				// TODO Auto-generated method stub
				super.paint(g);
				Point p = Map.getEnd();
				if (p!=null){
					g.drawRect(p.x*8,p.y*8,8,8);
				}
			}
		};
		drawPanel.setPreferredSize(new Dimension(200, 200));
		drawPanel.setBackground(Color.WHITE);
		drawPanel.addMouseListener(new MouseListener() {
			
			@Override
			public void mouseReleased(MouseEvent e) {
				int x = e.getX() / 8;
				int y = e.getY() / 8;
				Point p = new Point(x,y);
				if(state==1){
//					Map.createObstacle(thePoint)
				}else{
					if(state==2){
						Map.setEnd(new Point());
					}else{ Map.getStart();
					}
				}
			}
			
			@Override
			public void mousePressed(MouseEvent e) {
				
			}
			
			@Override
			public void mouseExited(MouseEvent e) {
				// TODO Auto-generated method stub
				
			}
			
			@Override
			public void mouseEntered(MouseEvent e) {
				// TODO Auto-generated method stub
				
			}
			
			@Override
			public void mouseClicked(MouseEvent e) {
				// TODO Auto-generated method stub
				
			}
		});
		
		drawPanel.addMouseMotionListener(new MouseAdapter(){
			public void mouseDragged(MouseEvent e){
		
			}
		});
}
	
	/**
	 * Initialisiert alle Toolbars.
	 */
	private void initToolbars() {
		// TODO implementieren

		toolbar = new JToolBar(); 
		JButton hindernis = new JButton("Hindernis");
		toolbar.add("Hindernis",hindernis);
		JButton endpunkt = new JButton("Endpunkt");
		toolbar.add("Endpunkt",endpunkt);
		JButton  startpunkt = new JButton ("Startpunkt");
		toolbar.add("Startpunkt",startpunkt);
		hindernis.addActionListener( new ActionListener() {
			public void actionPerformed(ActionEvent e){
				state=OBSTACLE;
			}			
		});
		endpunkt.addActionListener( new ActionListener() {
			public void actionPerformed(ActionEvent e){
				state=GOAL;
			}			
		});
		startpunkt.addActionListener( new ActionListener() {
			public void actionPerformed(ActionEvent e){
				state=START;
			}			
		});

		
	}

	/**
	 * Initialisiert die Applikation mit Startwerten.
	 * Wird auch beim Druecken des "Neu"-Buttons aufgerufen.
	 */
	private void initValues() {
		// TODO implementieren
	}
	
	/**
	 * Benutzt den Radiergummi unter Beachtung der ausgewaehlten
	 * Radiergroesse, um Hindernisse zu loeschen.
	 * @param thePoint der Mittelpunkt des zu radierenden Bereichs
	 */
	@SuppressWarnings("unused")
	private void useEraser(Point thePoint) {
		// TODO implementieren fuer Aufgabe 2
	}
	
	/**
	 * Hauptmethode
	 * @param args
	 */
	public static void main(String[] args) {
		Main me = new Main();
		me.init();
	}
}


map.java
Java:
import java.awt.Point;
import java.util.ArrayList;
import java.util.PriorityQueue;
import java.util.Set;
import java.util.HashSet;

/**
 * Datenstruktur, die Hindernisse, Start- und Endpunkt sowie den Pfad zwischen diesen verwaltet.
 * Der kuerzeste Pfad zwischen Start- und Endpunkt kann mit der Methode findPath() per A*-Algorithmus
 * berechnet und in die Datenstruktur eingetragen werden.
 *
 */
public class Map {
	private static PriorityQueue<GraphNode> openNodes;
	private static HashSet<GraphNode> closedNodes;
	private static ArrayList<GraphNode> buildList;

	private static GraphNode.Type[][] mapArray;

	public final static int WIDTH = 65;
	public final static int HEIGHT = 65;
	
	private static Point start;
	private static Point end;
	private static Set<Point> obstacles;
	private static Set<Point> path;

	protected static GraphNode.Type[][] getMap() {
		return mapArray;
	}

	private static GraphNode targetNode;
	private static GraphNode playerNode;

	/**
	 * Initialisiert die AStarMap.
	 * Muss mindestens einmal aufgerufen worden sein, bevor
	 * andere Methoden dieser Klasse verwendet werden koennen.
	 */
	public static void init() {
		mapArray = new GraphNode.Type[Map.WIDTH][Map.HEIGHT];
		obstacles = new HashSet<Point>();
		path = new HashSet<Point>();
		start = new Point(3, 3);
		
		for (int i = 0; i < Map.WIDTH; i++) {
			for (int j = 0; j < Map.HEIGHT; j++) {
				mapArray[i][j] = GraphNode.Type.EMPTY;
			}
		}
		mapArray[0][0] = GraphNode.Type.START;
		end = null;
	}
	
	/**
	 * Erstellt die Nachbarschaftsbeziehungen zwischen Knoten,
	 * die fuer den A*-Algorithmus noetig sind.
	 */
	private static void buildListForAStar() {
		buildList = new ArrayList<GraphNode>();

		for (int i = 0; i < WIDTH; i++) {
			for (int j = 0; j < HEIGHT; j++)
				buildList.add(new GraphNode(i, j));
		}

		for (int i = 0; i < WIDTH * (HEIGHT - 1); i++) {
			buildList.get(i).setSouth(buildList.get(i + WIDTH));
		}

		for (int i = WIDTH; i < WIDTH * HEIGHT; i++) {
			buildList.get(i).setNorth(buildList.get(i - WIDTH));
		}

		for (int i = 0; i < WIDTH * HEIGHT; i++) {
			if (i % WIDTH != 0)
				buildList.get(i).setWest(buildList.get(i - 1));
		}

		for (int i = 0; i < WIDTH * HEIGHT; i++) {
			if (i % WIDTH != (WIDTH - 1))
				buildList.get(i).setEast(buildList.get(i + 1));
		}
	}
	
	/**
	 * Sucht den kuerzesten Pfad zwischen Start- und Endpunkt unter Beachtung
	 * der Hindernisse und setzt ihn in das Feld.
	 * (Kuerzester Pfad im Sinne des Manhattan-Abstands,
	 * nicht euklidischer Abstand!)
	 */
	public static void findPath() {
		long time = System.nanoTime();

		if (buildList == null)
			buildListForAStar();

		for (GraphNode n : buildList)
			n.reset();

		playerNode = buildList.get(start.x * WIDTH + start.y);
		targetNode = buildList.get(WIDTH * end.x + end.y);

		openNodes = new PriorityQueue<GraphNode>();
		closedNodes = new HashSet<GraphNode>();

		GraphNode startNode = buildList.get(start.x * WIDTH + start.y);
		startNode.setDistance(0);
		openNodes.add(startNode);
		GraphNode tmp;
		
		int i = 0;

		while (!openNodes.isEmpty()) {
			i++;
			tmp = openNodes.poll();

			if (tmp == targetNode)
				break;

			addFriends(tmp);
		}

		GraphNode tmp2 = targetNode.getHome();
		if (tmp2 != null) {
			while (tmp2 != playerNode) {
				mapArray[tmp2.getX()][tmp2.getY()] = GraphNode.Type.PATH;
				path.add(new Point(tmp2.getX(), tmp2.getY()));
				tmp2 = tmp2.getHome();
			}
		}

		System.out.println("Nodes checked: " + i);
		System.out.println("Time needed (ms): " + (System.nanoTime() - time) / (1000*1000));
	}

	/**
	 * Finds out whether the specified GraphNode is an obstacle.
	 * @return the GraphNode to examine
	 */
	private static boolean isObstacle(GraphNode theNode) {
		return mapArray[theNode.getX()][theNode.getY()] == GraphNode.Type.OBSTACLE;
	}
	
	/**
	 * A*-relevante Berechnungen (closed und open list)
	 * @param node der aktuell zu berechnende Knoten
	 */
	private static void addFriends(GraphNode node) {
		closedNodes.add(node);

		GraphNode north = node.getNorth();
		GraphNode south = node.getSouth();
		GraphNode west = node.getWest();
		GraphNode east = node.getEast();

		if (north != null && !closedNodes.contains(north) && !isObstacle(north)) {
			if (node.getDistance() + 1 < north.getDistance()) {
				north.setHome(node);
				north.calculateDistance();
				north.calculateFitness();
			}
			if (!openNodes.contains(north))
				openNodes.add(north);
		}

		if (south != null && !closedNodes.contains(south) && !isObstacle(south)) {
			if (node.getDistance() + 1 < south.getDistance()) {
				south.setHome(node);
				south.calculateDistance();
				south.calculateFitness();
			}
			if (!openNodes.contains(south))
				openNodes.add(south);
		}

		if (west != null && !closedNodes.contains(west) && !isObstacle(west)) {
			if (node.getDistance() + 1 < west.getDistance()) {
				west.setHome(node);
				west.calculateDistance();
				west.calculateFitness();
			}
			if (!openNodes.contains(west))
				openNodes.add(west);
		}

		if (east != null && !closedNodes.contains(east) && !isObstacle(east)) {
			if (node.getDistance() + 1 < east.getDistance()) {
				east.setHome(node);
				east.calculateDistance();
				east.calculateFitness();
			}
			if (!openNodes.contains(east))
				openNodes.add(east);
		}
	}
	
	/**
	 * Setzt ein Hindernis.
	 * @param thePoint der Punkt, an den das Hindernis gesetzt werden soll.
	 */
	public static void createObstacle(Point thePoint) {
		if (!thePoint.equals(start) && !(thePoint.equals(end))) {
			obstacles.add(thePoint);
			mapArray[thePoint.x][thePoint.y] = GraphNode.Type.OBSTACLE;
		}
	}
	
	/**
	 * Loescht ein eventuell vorhandenes Hindernis.
	 * @param thePoint der Punkt, an dem das Hindernis gelöscht werden soll
	 */
	public static void deleteObstacle(Point thePoint) {
		if (!thePoint.equals(start) && !(thePoint.equals(end))) {
			mapArray[thePoint.x][thePoint.y] = GraphNode.Type.EMPTY;
			obstacles.remove(thePoint);
		}
	}
	
	/**
	 * Setzt den Startpunkt.
	 * @param thePoint der neue Startpunkt.
	 */
	public static void setStart(Point thePoint) {
		// alten Startpunkt loeschen
		mapArray[start.x][start.y] = GraphNode.Type.EMPTY;

		// Startpunkt setzen
		start = thePoint;
		mapArray[start.x][start.y] = GraphNode.Type.START;
	}
	
	/**
	 * Setzt den Endpunkt.
	 * @param thePoint der neue Endpunkt.
	 */
	public static void setEnd(Point thePoint) {
		// evt. alten Endpunkt loeschen
		if (end != null)
			mapArray[end.x][end.y] = GraphNode.Type.EMPTY;
		
		// Endpunkt setzen
		end = thePoint;
		mapArray[end.x][end.y] = GraphNode.Type.END;
	}
	
	public static void resetPath() {
		// Pfad zuruecksetzen
		for (Point itPoint : path) {
			mapArray[itPoint.x][itPoint.y] = GraphNode.Type.EMPTY;
		}
		path.clear();
	}
	
	/**
	 * Getter fuer den Startpunkt.
	 * @return der Startpunkt
	 */
	public static Point getStart() {
		return start;
	}
	
	/**
	 * Getter fuer den Endpunkt.
	 * @return der Endpunkt
	 */
	public static Point getEnd() {
		return end;
	}
	
	/**
	 * Getter fuer die Hindernisse.
	 * @return alle Hindernisse auf der Map
	 */
	public static Set<Point> getObstacles() {
		return obstacles;
	}
	
	/**
	 * Getter fuer den Path.
	 * Solle erst benutzt werden, wenn dieser mit findPath() berechnet wurde.
	 * @return der kuerzeste Pfad zwischen Start- und Endpunkt
	 */
	public static Set<Point> getPath() {
		return path;
	}
}

danke 🙂
 
wenn ich das programm starte und auf Endpunkt button klicke um den dann im Jpanel zu zeichnen kommt direkt nach dem klick

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at aStar_Prog.Map.setEnd(Map.java:246)
at aStar_Prog.Main$2.mouseReleased(Main.java:96)
at java.awt.Component.processMouseEvent(Unknown Source)
at javax.swing.JComponent.processMouseEvent(Unknown Source)
at java.awt.Component.processEvent(Unknown Source)
at java.awt.Container.processEvent(Unknown Source)
at java.awt.Component.dispatchEventImpl(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Window.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)
 
Wird denn die init() aus Map überhaupt jemals aufgerufen? Sonst ist mapArray nämlich null und es gibt eine NullPointerException beim Zugriff. Wieso ist eigentlich alles static?
 
Frag mich nicht, das war uns so vorgegeben mit dem statics...

ich weiss auch nicht ob die init jemals auf map ausgeführt wird.. ich seh da nämlich garnich durch ._.
 
Schau mal, was über init() steht:
Java:
    /**
     * Initialisiert die AStarMap.
     * Muss mindestens einmal aufgerufen worden sein, bevor
     * andere Methoden dieser Klasse verwendet werden koennen.
     */
Also musst du das wohl noch machen.
 
Du hast in der Klasse Main eine Methode init() die ganz sicher zu Beginn aufgerufen wird. Optimalerweise schreibst du da irgendwo rein [c]Map.init();[/c], dann wird das init() in der Klasse Map ausgeführt. Persönlich würde ich es zwar nie so machen, aber wenn das so vorgegeben ist, bleibt dir keine grosse Wahl.
 
Cool hat geklappt danke !! 🙂

und wie mache ich das jetzt das der was zeichnet !? ... das er den modus wechselt habe ich ja schon aber bisher kann ich nur doof rumklicken ohne das er ein 8x8 pixelgroßes rechtseck reinzaubert???

vielen dank! 🙂
 
Ahhh okay ich sehe gerade das ers doch zeichnet aber er es nicht aktualisiert im programm... also wenn ich irgendwo hinklicke dann passiert nichts... sobald ich jedoch meine toolbar herausziehe aktualisiert er das panel und mein klick ist zu sehen... warum das ???
 
In der Klasse Main hast du einen MouseListener, der mouseReleased(MouseEvent) überschreibt. Füge in diese Methode ganz am Schluss [c]drawPanel.repaint();[/c] ein.
 
ahh 🙂 supi

mhh jetzt habe ich ein komisches problem oder mach ich das total falsch .. immerhin kann ich jetzt schonmal ein eindpunkt setzen aber irgendwie kein hinderniss und startpunkt

Java:
private void initDrawPanel() {
		// TODO implementieren
		drawPanel = new JPanel() {
			@Override
			public void paint(Graphics g) {
				// TODO Auto-generated method stub
				super.paint(g);
				Point p = Map.getEnd();
				Point p2 = Map.getStart();
				if (p!=null){
					g.drawRect(p.x*8,p.y*8,8,8);
				if (p2!=null){
					g.drawRect(p.x*8,p.y*8,8,8);
				}
				}
			}
		};
		drawPanel.setPreferredSize(new Dimension(600, 600));
		drawPanel.setBackground(Color.WHITE);
		drawPanel.addMouseListener(new MouseListener() {
			
			@Override
			public void mouseReleased(MouseEvent e) {
				int x = e.getX() / 8;
				int y = e.getY() / 8;
				int x2 = e.getX() / 8;
				int y2 = e.getY() / 8;
				Point p = new Point(x,y);
				Point p2 = new Point(x2,y2);
				if(state==1){
					Map.createObstacle(p2);
				}else{
					if(state==2){
						Map.setEnd(p);
					}else{ Map.setStart(p);
					}
				}
				drawPanel.repaint();
 

Zurück
Oben