Java/Tutorials/Karteneditor Kapitel 6
Nun kommen wir zum Zeichnen unserer Tile. Wir erweitern unsere Klasse KartenAnsicht um die Methode zeichneTile(x,y), da wir als übergabe Werte die MausPosition erhalten im JPanel erhalten, müssen wir diese durch 32 Teilen um rauszufinden wo wir gerade geklickt haben in unseren IntegerArray. Nun holen wir uns mit fenster.aktuelleKarte.karte[x][y] die Aktuelle Karten Position und setzen die Akteulle TileID über unsere Klassenvariable von unsere Paletten Klasse.
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)); } public void zeichneTile(int x, int y) { x=x/32; y=y/32; fenster.aktuelleKarte.karte[x][y]=fenster.palette.aktuelleTile; } }
Nun können wir zwar unser Tile setzen, aber es wird in der Karte nicht Aktualisiert, wir könnte zwar nun ein einfaches repaint(); in unsere Methode zeichneTile() einsetzen, nur muss wirklich der Komplette Inhalt neugezeichnet werden? Natürlich nicht. Es wäre ja auch zu rechenintensiv, weil ja jedes mal der Komplette JScrollPane Inhalt gezeichnet werden musss um dies zu umgehen gibt es zwar die Methode repaint(x,y,breite,höhe) nur dies ist eine AWT Methode und der Bildschirminhalt wird nicht neugezeichnet. Die Swing Klasse stellt uns aber einen RepaintManager zur Verfügung, womit man Regionen im Fenster neuzeichnen kann, darum legen wir uns eine Klassenvariable vom Typ RepaintManager an und anschließend hohlen wir uns den RepaintManager von unsere KartenFenster-Klasse. Die RepaintManager Klasse gibt es nur für Fensterklassen von Swing, daher nur JFrame, JWindow. Darum müssen wir uns zunächst die Position unsere JScrollPane hohlen das unser JPanel beinhaltet dies erfolgt mit scroll.getLocaltion und dann x und y Wert. Wir benötigen aber auch noch die Höhe der Titelleiste uneseres Fensters sowie den linken Rand des Fensters. Daher hohlen wir uns diese Angaben mit getInsets(), wobei top für die titelleiste steht und left die größe der Umrandung links beinhaltet. Nun benötigen wir nur noch die Aktuelle Position in unseren JScrollPane, wenn wir diese haben. Nun Addieren wir diese Werte und ziehen die Position des JScrollPane ab und rufen über unseren RepaintManager die Methode addDirtyRegion auf, wo wir dann unser Fenster, an der geklickten Position neuzeichnen lassen.
public class KartenAnsicht extends JPanel{ KartenFenster fenster; JScrollPane scroll=new JScrollPane(); RepaintManager m; public KartenAnsicht(KartenFenster kfenster) { scroll.setViewportView(this); fenster=kfenster; //verhindert Flackern setDoubleBuffered(true); changeKarte(); m=RepaintManager.currentManager(fenster); } 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)); } public void zeichneTile(int x, int y) { x=x/32; y=y/32; fenster.aktuelleKarte.karte[x][y]=fenster.palette.aktuelleTile; Rectangle r=scroll.getViewport().getViewRect(); int dx=this.scroll.getLocation().x+fenster.getInsets().left-r.x; int dy=this.scroll.getLocation().y+fenster.getInsets().top-r.y; m.addDirtyRegion(fenster , dx+x*32, dy+y*32, 32, 32); } }
Nun kommen wir zu den Mausereignissen. Die Tile sollen gezeichnet werden wenn wir auf einen Punkt Klicken und wenn wir die Maustaste gedrückt halten und über die Karte fahren lassen. Daher fügen wir unseren JPanel noch ein MouseListener und ein MouseMotionListener hinzu wo wir dann anschließend die Methode zeichneTile aufrufen und mit e.getX() und e.getY() die Position der Maus auf unseren JPanel übermitteln. Da wir nicht alle Mausereignisse verarbeiten müssen, verwenden wir nicht MouseListener sondern MouseAdapter, dadruch müssen wir nicht alle Mausereignisse implementieren. MouseDragged steht übrigens für bewegen der Maus mit gedrückter Maustaste.
public class KartenAnsicht extends JPanel{ KartenFenster fenster; JScrollPane scroll=new JScrollPane(); RepaintManager m; public KartenAnsicht(KartenFenster kfenster) { scroll.setViewportView(this); fenster=kfenster; //verhindert Flackern setDoubleBuffered(true); changeKarte(); m=RepaintManager.currentManager(fenster); addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { zeichneTile(e.getX(), e.getY()); } }); addMouseMotionListener(new MouseMotionAdapter() { @Override public void mouseDragged(MouseEvent e) { zeichneTile(e.getX(), e.getY()); } }); } 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)); } public void zeichneTile(int x, int y) { x=x/32; y=y/32; fenster.aktuelleKarte.karte[x][y]=fenster.palette.aktuelleTile; Rectangle r=scroll.getViewport().getViewRect(); int dx=this.scroll.getLocation().x+fenster.getInsets().left-r.x; int dy=this.scroll.getLocation().y+fenster.getInsets().top-r.y; m.addDirtyRegion(fenster , dx+x*32, dy+y*32, 32, 32); } }
Um unseren Editor bereits vorab zu Testen, muss man in der Klasse TilePalette die Klassenvariable aktuelleTile von 0 z.B. auf 2 setzen
class TilePalette extends JPanel{ ... int aktuelleTile=2; ,.. }
Und wenn wir unser Programm starten, können wir nun ein Tile auf unserer Karte verändern.
Wie man das aktuell verwendete Tile ändern kann, folgt im nächsten Kapitel.