Java/Tutorials/Karteneditor Kapitel 5
In diesen Kapitel behandeln wir wie wir die Karte im Fenster Anzeigen lassen. Hierfür erstellen wir eine neue Klasse KartenAnsicht und leiten diese von JPanel ab. Wir übergen wieder unser KartenFenster im Konstruktor, so das wir auf die Karte zugreifen können. Weiterhin werden wir wieder die paintComponent()-Methode Implementieren. Und wir aktivieren Double Buffered, dies verhindert Flackern.
public class KartenAnsicht extends JPanel{ KartenFenster fenster; public KartenAnsicht(KartenFenster kfenster) { fenster=kfenster; //verhindert Flackern setDoubleBuffered(true); } public void paintComponent(Graphics g) { } }
Kommen wir jetzt einmal zu einigen Swing Komponenten die wir brauchen und zwar JScrollPane. Wir wissen das unsere Karten sehr groß wird und wenn wir alles auf einmal Zeichnen lassen würden, würde unnötig Rechenleistung verbraten, daher gibt es genau 2 Gründe warum wir JScrollPane verwenden sollten. Einmal um uns auf unserer Karte mit Scrollbars zu bewegen und um Rechenleistung zu sparen. Über die Methode setViewport, sagen wir was wir betrachten wollen. In unseren Fall, wollen wir das unsere Klasse selbst die zu betrachtende Komponete ist.
public class KartenAnsicht extends JPanel{ KartenFenster fenster; JScrollPane scroll=new JScrollPane(); public KartenAnsicht(KartenFenster kfenster) { fenster=kfenster; scroll.setViewportView(this); //verhindert Flackern setDoubleBuffered(true); } public void paintComponent(Graphics g) { } }
Warum wir JScrollPane noch brauchen werdet ihr nun sehen. Die Swing Komponente JScrollPane verfügt über die Methode getViewport(), mit diser Methode können wir uns ein JViewport zurückgeben. Mit dieser Klasse können wir uns mit der Methode getViewRect() die Aktuelle Position und die größe der Ansicht auf dem JPanel zurück geben lassen. Man kann sich JViewport wie ein Fenster vorstellen, womit wir uns eine Wand ansehen können. Und mit der Methode getViewRect() können wir uns die Position des Fensters und die Größe auf der Wand zurückgeben lassen.
public class KartenAnsicht extends JPanel{ KartenFenster fenster; JScrollPane scroll=new JScrollPane(); public KartenAnsicht(KartenFenster kfenster) { scroll.setViewportView(this); fenster=kfenster; //verhindert Flackern setDoubleBuffered(true); } public void paintComponent(Graphics g) { Rectangle r=scroll.getViewport().getViewRect(); } }
Die Klasse Rectangle beschreibt ein Rechteck. Nun wollen wir anfangen zu Zeichnen, nur wir benötigen die Position der linken obere Ecke, weil wir wollen ja nicht die komplette Karten Zeichnen sondern nur einen Teil, würden wir die Komplette Karten zeichnen lassen, währe es sehr rechen Intensiv. Die Klasse Rectangle stellt uns diese Variablen alle zur Verfügung. Zuerst hohlen wir uns die Koordinaten x und y der linken oberen Ecke, anschließend hohlen wir uns die Breite (width) und die Höhe (height). Die höhe und breite verrechnen wir anschließend mit x und y, so das wir am Ende 2 Punkte haben.
public class KartenAnsicht extends JPanel{ KartenFenster fenster; JScrollPane scroll=new JScrollPane(); public KartenAnsicht(KartenFenster kfenster) { scroll.setViewportView(this); fenster=kfenster; //verhindert Flackern setDoubleBuffered(true); } public void paintComponent(Graphics g) { Rectangle r=scroll.getViewport().getViewRect(); int startx=r.x; int starty=r.y; int endx=startx+r.width; int endy=starty+r.height; startx=startx/32; starty=starty/32; endx=endx/32; endy=endy/32; } }
Diese Teilen wir durch die Tilegröße, also 32, so das wir mit ihrer hilfe eine forschleife durchlaufen können. Als startwert geben wir nicht 0, sondern startx, an, so das nicht die komplette Karte gezeichnet wird, sondern nur ein Teilausschnitt. Über die Klassevariable fenster hohlen wir uns unsere Karte und wir können die Methode getTileImage verwenden um uns ein Tile auf der Karte zu zeichnen, was wir benötigen. Anschließend Zeichnen wir das Tile in unserer Ansicht.
public class KartenAnsicht extends JPanel{ KartenFenster fenster; JScrollPane scroll=new JScrollPane(); public KartenAnsicht(KartenFenster kfenster) { scroll.setViewportView(this); fenster=kfenster; //verhindert Flackern setDoubleBuffered(true); } public void paintComponent(Graphics g) { Rectangle r=scroll.getViewport().getViewRect(); int startx=r.x; int starty=r.y; int endx=startx+r.width; int endy=starty+r.height; startx=startx/32; starty=starty/32; endx=endx/32; endy=endy/32; for(int x=startx;x < endx;x++) { for(int y=starty;y < endy;y++){ BufferedImage tile=fenster.aktuelleKarte.getTileImage(x, y); g.drawImage(tile, x*32, y*32, this); } } } }
Nun, fehlt nur noch das wir unser JPanel eine Feste größe geben, so das man mit unser JScrollPane auch richtig scrollen kann. Diese verpacken wir in eine extra Methode, so das wir später wenn wir die Karte wechseln, diese größe schnell ändern können. Diese Methode nennen wir changeKarte(). In dieser hohlen wir uns die Breite und Höhe des Karten Integer-Array und Mutliplizieren dies mit unserer Pixelgröße also 32 und verwenden wieder die Methode setPreferredSize().
public class KartenAnsicht extends JPanel{ KartenFenster fenster; JScrollPane scroll=new JScrollPane(); public KartenAnsicht(KartenFenster kfenster) { scroll.setViewportView(this); fenster=kfenster; //verhindert Flackern setDoubleBuffered(true); changeKarte(); } public void paintComponent(Graphics g) { Rectangle r=scroll.getViewport().getViewRect(); int startx=r.x; int starty=r.y; int endx=startx+r.width; int endy=starty+r.height; startx=startx/32; starty=starty/32; endx=endx/32; endy=endy/32; for(int x=startx;x < endx;x++) { for(int y=starty;y < endy;y++){ BufferedImage tile=fenster.aktuelleKarte.getTileImage(x, y); g.drawImage(tile, x*32, y*32, this); } } } public void changeKarte() { //Hier wird nun eine Feste größe des JPanel gesetzt. int dx=fenster.aktuelleKarte.karte.length; int dy=fenster.aktuelleKarte.karte[0].length; setPreferredSize(new Dimension(dx*32,dy*32)); } }
Nun wollen wir uns doch mal unsere Karten Anzeigen lassen. Darum erweitern wir unsere Klasse KartenFenster. Einmal legen wir uns eine Klassenvariable die vom Typ KartenAnsicht ist. Anschließend Intialisieren wir unsere Klassenvariable, wieder nach der Initialiserung von unseren aktuellen Karte und fügen unsere Ansicht dem Fenster in der Mitte(BorderLayout.CENTER) hinzu. Dabei ist zu beachten, das wir nicht unsere Klassenvariable übergeben, sondern unsere JScrollPane, daher schreiben wir in der Methode add() nicht ansicht sondern ansicht.scroll.
public class KartenFenster extends JFrame{ Karte aktuelleKarte; TilePalette palette; KartenAnsicht ansicht; public KartenFenster() { this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.requestFocus(); int karte[][]=new int[100][100]; String name="Unser erste Karte"; String tilesetDateiname="Tileset.png"; aktuelleKarte=new Karte(karte, tilesetDateiname, name); palette=new TilePalette(this); //Initialisere KartenAnsicht ansicht=new KartenAnsicht(this); setLayout(new BorderLayout()); add(palette, BorderLayout.WEST); add(ansicht.scroll , BorderLayout.CENTER); //größe des Fensters setzen setSize(1024, 768); //Setzen eines Fenstertitels setTitle("Karteneditor"); } }
Von nun an ist es nicht mehr sehr Weit zu unseren Fertigen Karteneditor.