# JPanel und Grid aus Hexagons



## TheWicked (9. Apr 2012)

Hallo zusammen! 

Wir arbeiten an einem MapEditor. Dank dem Button "New Map" kann der Benutzer ein Spielfeld mit gewünschter Grösse initialisieren. Das Spielfeld besteht dann aus entsprechend vielen Hexagone. Der Anfangszustand der Hexagone ist blau (die Map besteht nur aus Wasser). Der Benutzer kann im nächsten Schritt dank Buttons (Wald,Wiese,Wasser,Fels) einzelne Hexagons neu färben.


Ziel des Editors:

Die Attribute der Hexagons werden in einem dahinterliegenden 2Dim.Array gespeichert.
Beispiel:

Das erste Hexagon wird grün gefärbt. Die Information grün wird im Array[0][0] gespeichert.
Die einzelnen Informationen sind dann in einer Tabelle gespeichert und haben somit eine Position auf der Karte. Dies ist für die nächste Instanz wichtig, denn sie zeichnet die Map - grün würde in dem Fall eine Wiese ergeben.

Meine Probleme:

1) Wenn ich mein "HexGrid" in einem JPanel öffnen will geschieht nichts (in einem JFrame aber schon)
2)Wie kann ich dem einzelnen Hexagon einen MouseListener geben? (also wie kann ich einzelne Hexagons durch Mausklick verändern?)

Hier ist mein bestehender code:

ps: die zwei Polygonen pi & po (polygon in & polygon out) werden übereinander gezeichnet. Pi ist kleiner als po. Der grössere wird schwarz bemalt, damit der Effekt eines Randes entsteht.


```
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Polygon;

public class Hexagon {

	Polygon pi;
	Polygon po;
	int posx;
	int posy;
	String color;

	Hexagon(int posx, int posy, String color) {
        this.color = color;
        this.posx = posx;
        this.posy = posy;
        
        pi = new Polygon();
        po = new Polygon();
	}
    
    public void draw(Graphics g) {
        // draw outline
        for (int i = 0; i < 6; i++) {
			po.addPoint((int) (posx + 32 * Math.cos(i * 2 * Math.PI / 6)),
                        (int) (posy + 32 * Math.sin(i * 2 * Math.PI / 6)));
        }
        
		g.setColor(Color.BLACK);
		g.fillPolygon(po);
        
        // draw inside
		for (int i = 0; i < 6; i++)
			pi.addPoint((int) (posx + 30 * Math.cos(i * 2 * Math.PI / 6)),
                        (int) (posy + 30 * Math.sin(i * 2 * Math.PI / 6)));
        
		// set color
        if (color.equals("YELLOW")) {
			g.setColor(Color.YELLOW);
			g.fillPolygon(pi);
		} else if (color.equals("CYAN")) {
			g.setColor(Color.CYAN);
			g.fillPolygon(pi);
		} else if (color.equals("GREEN")) {
			g.setColor(Color.GREEN);
			g.fillPolygon(pi);
		} else if (color.equals("MAGENTA")) {
			g.setColor(Color.MAGENTA);
			g.fillPolygon(pi);
		}
    }
}
```



```
import java.awt.Color;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.Panel;
import java.awt.Polygon;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.swing.JFrame;
import javax.swing.JPanel;

class HexGrid extends JPanel {


	private static final long serialVersionUID = 1L;
	Hexagon[][] hexArray;
	int height;
	int length;
	
	HexGrid(int length,int height){
		this.height= height;
		this.length= length;
	}

	public void paintComponent(Graphics g) {

		int posx = 35;
		int posy = 35;
		
		hexArray = new Hexagon[height][length];


			for (int i = 0; i <= length - 1; i++) {
				for(int j=0;j<=height-1;j++){
				hexArray[j][i] = new Hexagon(posx, posy, "CYAN");
				hexArray[j][i].draw(g);
				posy = posy + 53;
				}
				posx=posx+47;
				if (posy == 35+height*53)posy=62;
				else posy=35;
			}
	}
}
```



Vielen Dank


----------



## Marco13 (9. Apr 2012)

1. Das Panel, wo das hexGrid reinkommt, braucht einen passenden LayoutManager und/oder das HexGrid eine passende PreferredSize. Also entweder
panel.setLayout(new GridLayout(1,1));
panel.add(hexGrid);
oder 
hexGrid.setPreferredSize(new Dimension(300,300));

2. Einzelne MouseListener gehen so nicht, man wird IMMER ausrechnen müssen, in welchem Feld geklickt wurde (MouseListener arbeiten auf Components, und die sind Rechteckig). Schau mal ob dir sowas wie http://www.java-forum.org/mathematik/106028-problem-sechsecken.html oder andere Forensuchergebnisse helfen.


----------



## TheWicked (13. Apr 2012)

Hallo Leute!

Hier ist eine provisorische Lösung - falls jemand das gleiche Problem hat

Sie ist provisorisch, denn das Panel wird erst verzögert aktualisiert. (Weiss jemand auch warum???)

zu 1) Da habe ich Marcos ersten Rat befolgt.

zu 2) 

Weil man die Position des Mittelpunkts aller Hexagonen kennt (sie sind in hexArray[].posx/hexArray[].posy gepseichert), kann man auch ihre Distanz zur Maus berechnen. Diese wird in mouseDistance [] abgespeichert. Bsp: mouseDistance [0] gibt den Abstand von hexArray[0] zur Maus.
mouseDistance [1] gibt den Abstand von hexArray[1] zur Maus usw... 


Die Methode minMouseDist() geht durch das mouseDistance-Array und wiedergibt den Index des Arrays mit dem kleinsten Wert. Dieser Index entspricht dann auch dem Index des entsprechenden Hexagons im hexArray. (siehe oben)

dank diesem Index i kann man beliebig die Werte des Hexagons in heyArray_ verändern.



		Java:In die Zwischenablage kopieren


import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import javax.swing.JFrame;
import javax.swing.JPanel;

public class HexGridGUI extends JFrame {

	private static final long serialVersionUID = 1L;
	private JPanel HexPanel;
	private JFrame HexFrame;

	int height;
	int length;
	static int[] mouseDistance; // benötigt um das angeklickte feld zu lokalisieren.
	static int mouseX;
	static int mouseY;
	HexGrid d;

	// Konstruktor
	public HexGridGUI(int length, int height) {
		{
			this.setSize(294, 182);
		}

		HexFrame = new JFrame();
		HexFrame.setVisible(true);
		HexFrame.setDefaultCloseOperation(EXIT_ON_CLOSE);
		HexFrame.setSize(500, 500);
		HexPanel = new JPanel();
		HexPanel.setLayout(new GridLayout(1, 1));
		d = new HexGrid(length, height);
		HexPanel.add(d);
		HexPanel.addMouseListener(handler);
		HexFrame.add(HexPanel);
		mouseDistance = new int[length * height];
	}

	// Klasse für den MausListener + Methoden
	HandlerClass handler = new HandlerClass();

	private class HandlerClass implements MouseListener {

		@Override
		public void mouseClicked(MouseEvent e) {

			mouseX = e.getX();
			mouseY = e.getY();

			for (int i = 0; i < HexGrid.hexArray.length; i++) {
				mouseDistance[i] = Math.abs(HexGrid.hexArray[i].posx - mouseX)
						+ Math.abs(HexGrid.hexArray[i].posy - mouseY);
			}

			int index = minMouseDist(mouseDistance); //

			
				HexGrid.hexArray[index].color = Color.GREEN;
				HexPanel.revalidate();
				HexPanel.repaint();
			
		}

		@Override
		public void mouseEntered(MouseEvent e) {
			// TODO Auto-generated method stub

		}

		@Override
		public void mouseExited(MouseEvent e) {
			// TODO Auto-generated method stub

		}

		@Override
		public void mousePressed(MouseEvent e) {
			// TODO Auto-generated method stub

		}

		@Override
		public void mouseReleased(MouseEvent e) {
			// TODO Auto-generated method stub

		}
	}

	// durchkämmt das Array, welches die Distanzen zwischen MausPosition und
	// Mittelpunkte der Hexagonen enthält

	int minMouseDist(int[] mouseDistance) {
		int hilfsVar;
		int i = 0;
		int j = 1;

		while (j < mouseDistance.length) {
			if (mouseDistance[i] < mouseDistance[j]) {
				j++;
			} else {
				hilfsVar = i;
				i = j;
				j = hilfsVar;
				j++;
			}
		}
		return i; // Ist ein Index. Im hexArray [i] befindet sich das gesuchte Element
	}

	public static void main(String[] args) {

		new HexGridGUI(10, 10);

	}
}




		Java:In die Zwischenablage kopieren


import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JPanel;

class HexGrid extends JPanel {

	private static final long serialVersionUID = 1L;

	static public Hexagon[] hexArray;
	public int height;
	public int length;

	HexGrid(int length, int height) {

		this.height = height;
		this.length = length;
		hexArray = new Hexagon[height * length];

		int posx = 35;
		int posy = 35;
		int a = 0;
		for (int i = 0; i <= height - 1; i++) {
			for (int j = 0; j <= length - 1; j++) {
				hexArray[a] = new Hexagon(posx, posy, Color.CYAN);
				posx = posx + 53;
				a++;
			}
			posy = posy + 47;
			if (posx == 35 + length * 53)
				posx = 62;
			else
				posx = 35;
		}
	}

	void changeGridInformation(int i, Color c) {
		hexArray[i].color = c;
	}

	public void paintComponent(Graphics g) {

		for (int i = 0; i <= length * height - 1; i++) {
			hexArray[i].draw(g);
		}
	}
}




		Java:In die Zwischenablage kopieren


import java.awt.Color;
import java.awt.Graphics;
import java.awt.Polygon;

public class Hexagon {

	Polygon pi;
	Polygon po;
	int posx;
	int posy;
	Color color;

	Hexagon(int posx, int posy, Color color) {
		this.color = color;
		this.posx = posx;
		this.posy = posy;

		pi = new Polygon();
		po = new Polygon();
	}

	public void draw(Graphics g) {

		// draw outline
		for (int i = 0; i < 6; i++) {
			po.addPoint((int) (posx + 32 * Math.sin(i * 2 * Math.PI / 6)),
					(int) (posy + 32 * Math.cos(i * 2 * Math.PI / 6)));
		}

		g.setColor(Color.BLACK);
		g.fillPolygon(po);

		// draw inside
		for (int i = 0; i < 6; i++)
			pi.addPoint((int) (posx + 30 * Math.sin(i * 2 * Math.PI / 6)),
					(int) (posy + 30 * Math.cos(i * 2 * Math.PI / 6)));

		g.setColor(color);
		g.fillPolygon(pi);
	}
}

_


----------



## Michael... (13. Apr 2012)

Hab's nur im Schnelldurchgang überflogen:

Warum packst Du um das HexGrid noch ein JPanel (HexPanel)?  Das HexGrid ist doch bereits ein JPanel.
Ruf mal repaint direkt auf dem HexGrid auf. Ein validate() ist nicht nötig und nutzt evtl. auch nichts, da sich am Layout nichts geändert hat.


----------



## TheWicked (13. Apr 2012)

Ja du hast recht, da ist ein Panel zuviel  das hat leider das verzögerte reagieren nicht verbessert :S


----------



## Marco13 (13. Apr 2012)

Was meinst du mit "verzögert"? 

Das
 HexFrame.setVisible(true);
sollte GANZ am Ende gemacht werden, wenn alles zusammengebaut ist. (BTW: Variablennamen im camelCase, also "hexFrame" bzw. einfach "frame" statt "HexFrame")


----------



## bERt0r (13. Apr 2012)

Schau ich hab dir was gezaubert:


----------



## TheWicked (17. Apr 2012)

Hallo!

@ Marco13: Ja ich werde in Zukunft auf die Namensgebung achten - ich habe selber ein riesen Durcheinander deswegen  
Verzögert ist es in dem Sinn, dass wenn ich ein Feld anklicke nichts gschieht bzw. ich muss ein neues Feld anklicken damit beide neu bemalt werden :S auch verschwindet das Spielfeld ab und zu wenn ich die Fenstergrösse verändere. An meiner GraKa kann das wohl nicht liegen, denn das Beispiel von bERt0r funktioniert blendend - wobei ich jetzt zu bERt0r komme:

@ bERtor viel Dank! jenachdem, falls meine Ursprungsversion nicht funktioniert, werde ich mich von deiner inspirieren lassen  Die funktioniert wunderbar und hat keine Verzögerungen! Auch schau ich dir ab wie du das Problem mit dem jScrollpane gelöst hast - hab schon Stunden versenkt nur weil ich nicht wusste wie man "this.setPreferredSize();" verwendet 

ein riesen Dankschön an euch!


----------



## TheWicked (17. Apr 2012)

Jeah!! ich habe die Lösung! im Code habe ich zwei draw Methoden... das ist völlig unsinnig! und "super.paint();" habe ich auch nie verwendet. Sobald ich alles schön hingekriegt habe, Poste ich das Resultat!


----------



## TheWicked (18. Apr 2012)

So da ist es:


```
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.border.EmptyBorder;


public class HexGridGUI extends JFrame {

	private static final long serialVersionUID = 1L;
	JPanel contentPane;
	HexGrid HexGrid;
	int height;
	int length;
	static int[] mouseDistance; // benötigt um das angeklickte feld zu
								// lokalisieren.
	static int mouseX;
	static int mouseY;
	HexGrid d;

	// Konstruktor
	public HexGridGUI(int length, int height) {

		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setBounds(100, 100, 450, 300);

		contentPane = new JPanel();
		contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
		contentPane.setLayout(new BorderLayout(0, 0));
		setContentPane(contentPane);

		JScrollPane scrollPane = new JScrollPane();
		contentPane.add(scrollPane, BorderLayout.CENTER);

		HexGrid = new HexGrid(length, height);
		HexGrid.addMouseListener(handler);

		mouseDistance = new int[length * height];

		scrollPane.setViewportView(HexGrid);
		pack();
	}

	// HexGrid HexGrid = new HexGrid(length,height);

	// Klasse für den MausListener + Methoden
	HandlerClass handler = new HandlerClass();

	private class HandlerClass implements MouseListener {

		@Override
		public void mouseClicked(MouseEvent e) {

			mouseX = e.getX();
			mouseY = e.getY();

			for (int i = 0; i < HexGrid.hexArray.length; i++) {
				mouseDistance[i] = Math.abs(HexGrid.hexArray[i].posx - mouseX)
						+ Math.abs(HexGrid.hexArray[i].posy - mouseY);
			}
			int index = minMouseDist(mouseDistance);
			
			HexGrid.hexArray[index].colorin = Color.GREEN;
			HexGrid.hexArray[index].colorout = Color.red;
			HexGrid.hexArray[index].einheit = "Inf";			
			HexGrid.repaint();
		}

		@Override
		public void mouseEntered(MouseEvent arg0) {
			// TODO Auto-generated method stub
			
		}

		@Override
		public void mouseExited(MouseEvent arg0) {
			// TODO Auto-generated method stub
			
		}

		@Override
		public void mousePressed(MouseEvent arg0) {
			// TODO Auto-generated method stub
			
		}

		@Override
		public void mouseReleased(MouseEvent arg0) {
			// TODO Auto-generated method stub
			
		}
	}

	// durchkämmt das Array, welches die Distanzen zwischen MausPosition und
	// Mittelpunkte der Hexagonen enthält
	int minMouseDist(int[] mouseDistance) {
		int hilfsVar;
		int i = 0;
		int j = 1;

		while (j < mouseDistance.length) {
			if (mouseDistance[i] < mouseDistance[j]) {
				j++;
			} else {
				hilfsVar = i;
				i = j;
				j = hilfsVar;
				j++;
			}
		}
		return i; // Ist ein Index. Im hexArray [i] befindet sich das gesuchte
					// Element
	}

	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					HexGridGUI frame = new HexGridGUI(10, 10);
					frame.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}
}

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JPanel;

class HexGrid extends JPanel {

	private static final long serialVersionUID = 1L;
	static public Hexagon[] hexArray;
	public int height;
	public int length;

	HexGrid(int length, int height) {

		this.height = height;
		this.length = length;
		hexArray = new Hexagon[height * length];

		int posx = 35;
		int posy = 35;
		int a = 0;
		for (int i = 0; i <= height - 1; i++) {
			for (int j = 0; j <= length - 1; j++) {
				hexArray[a] = new Hexagon(posx, posy, Color.CYAN, Color.black);
				posx = posx + 53;
				a++;
			}
			posy = posy + 47;
			if (posx == 35 + length * 53)
				posx = 62;
			else
				posx = 35;
		}
		this.setPreferredSize(new Dimension(58 * length, 58 * height));
	}

	/*
	 * void changeGridInformation(int i, Color ci,Color co) {
	 * hexArray[i].colorin = ci; hexArray[i].colorout= co; }
	 */

	public void paintComponent(Graphics g) {
		super.repaint();

		for (int i = 0; i <= length * height - 1; i++) {
			g.setColor(hexArray[i].colorout);
			g.fillPolygon(hexArray[i].po);
		}

		for (int i = 0; i <= length * height - 1; i++) {
			g.setColor(hexArray[i].colorin);
			g.fillPolygon(hexArray[i].pi);
			g.setColor(Color.black);
			g.drawString(hexArray[i].einheit, hexArray[i].posx-5,
					hexArray[i].posy+5);
		}

	}
}

import java.awt.Color;
import java.awt.Polygon;

public class Hexagon {

	Polygon pi;
	Polygon po;
	int posx;
	int posy;
	Color colorin;
	Color colorout;
	String einheit="";

	Hexagon(int posx, int posy, Color colorin, Color colorout) {
		this.colorin = colorin;
		this.colorout = colorout;
		this.posx = posx;
		this.posy = posy;

		pi = new Polygon();
		po = new Polygon();
		
		// draw outline
		for (int i = 0; i < 6; i++) {
			po.addPoint((int) (posx + 32 * Math.sin(i * 2 * Math.PI / 6)),
					(int) (posy + 32 * Math.cos(i * 2 * Math.PI / 6)));
		}
		for (int i = 0; i < 6; i++)
			pi.addPoint((int) (posx + 30 * Math.sin(i * 2 * Math.PI / 6)),
					(int) (posy + 30 * Math.cos(i * 2 * Math.PI / 6)));
	}
}
```


----------

