Java ja grafiikka Ville Sundberg 12.12.2007
What happen Viritetty JPanel Graphics ja Graphics2D ImageIO ja BufferedImage Animaatio ja ajastus Optimoinnista
Kehykset import javax.swing.jframe; public class Piirto { public static void main(string[] args) { JFrame frame = new JFrame("Piirto"); frame.add(new Piirtopaneeli()); frame.setdefaultcloseoperation(jframe.exit_on_close); frame.pack(); frame.setlocationrelativeto(null); frame.setvisible(true);
Piirtopaneeli 0.1 public class Piirtopaneeli extends JPanel { public Piirtopaneeli() { this.setpreferredsize(new Dimension(800, 520)); protected void paintcomponent(graphics g) {
Kaiken ydin Tämänniminen metodi määrää komponentin ulkoasun. Voimme piirtää mitä tahansa, jos ylikirjoitamme sen. protected void paintcomponent(graphics g) { Tämä on grafiikkakonteksti eli olio, jonka avulla piirtäminen onnistuu. Piirtojärjestelmä luo sen meille aivan automaattisesti.
Piirtopaneeli 0.5 public class Piirtopaneeli extends JPanel { public Piirtopaneeli() { this.setpreferredsize(new Dimension(400, 300)); protected void paintcomponent(graphics g) { g.setcolor(color.green); g.fillrect(100, 100, 200, 170); g.setcolor(color.red); g.filloval(500, 250, 200, 200); // ( x, y, leveys, korkeus)
Graphics2D Graphics on todellisuudessa vanhentunutta tekniikkaa. Graphics2D g2d = (Graphics2D) g; Nykyisin Graphics-muuttujassa piilee Graphics2D-olio, jonka saamme käyttöön tyyppimuunnoksen avulla. Graphics2D:n API on yhtenäisempi ja sillä voi piirtää monipuolisemmin. (Kaikki vanhatkin konstit ovat käytössä.)
Piirtopaneeli 1.0 protected void paintcomponent(graphics g) { Graphics2D g2d = (Graphics2D) g; g2d.setcolor(color.green); g2d.fill(new Rectangle(100, 100, 200, 170)); g2d.setcolor(color.red); g2d.fill(new Ellipse2D.Double(500, 250, 200, 200)); Metodi fill ottaa parametrinaan geneerisen Shape-olion eli muodon. Sekä Rectangle että Ellipse2D.Double ovat muotoja.
Sudit ja maalit Graphics2D-luokka tukee erilaisia piirtomoodeja. g2d.setstroke(new BasicStroke(15f)); setstroke-metodilla asetetaan mm. reunojen ja viivojen piirtotapa. Tässä luodaan uusi, 15 pikselin levyinen Perussuti. g2d.setpaint(new GradientPaint(... )); setpaint-metodilla taas vaikutetaan alueiden täyttötapaan.
Piirtopaneeli 1.1 protected void paintcomponent(graphics g) {... g2d.setcolor(color.green); g2d.fill(new Rectangle(100, 100, 200, 170)); g2d.setpaint(new GradientPaint(new Point(0,0), Color.blue, new Point(50,50), Color.black, true)); g2d.fill(new Ellipse2D.Double(500, 250, 200, 200));
Piirtopaneeli 1.2 protected void paintcomponent(graphics g) {... g2d.setrenderinghint(renderinghints.key_antialiasing, RenderingHints.VALUE_ANTIALIAS_ON); g2d.setcolor(color.magenta); g2d.setstroke(new BasicStroke(10f)); g2d.drawpolyline(new int[] { 100, 400, 400, 700, new int[] { 400, 400, 100, 100, 4);
Kuvien lataaminen Image-luokka määrittelee geneerisen kuvan. Tällainen kuva voidaan antaa Graphics-oliolle piirrettäväksi. Image tausta =... Java-API on uskomattoman sekava kuvien lataamisen suhteen. Erilaisia tapoja on jopa kymmeniä. tausta = ImageIO.read(new File(...)); Hyvä yleiskäyttöinen kuvanlatausmekanismi on ImageIO.read(File), joka tukee useita kuvaformaatteja.
Kuvien (ja kuviin) piirtäminen Graphics2D tarjoaa monipuoliset työkalut kuvien piirtämiseen. g2d.drawimage(image, x, y, null); Kuvienpiirtämismetodien viimeistä parametria, ImageObserver-oliota, käytetään harvoin applettien ulkopuolella. BufferedImage kuva = ImageIO.read(...); Graphics2D g2 = kuva.creategraphics(); Kuvaan voi piirtää samalla tavalla kuin JPaneliinkin sillä erotuksella että kuvaan piirretyt asiat jäävät talteen.
Piirtopaneeli 1.3 private Image tausta; public Piirtopaneeli() { try { this.tausta = ImageIO.read(new File("atmosphere.jpg")); catch (IOException e) { e.printstacktrace(); System.exit(1); protected void paintcomponent(graphics g) { g2d.drawimage(tausta, 0, 0, null);... g2d.fill(new Ellipse2D.Double(...));
Liikkuva kuva Olioihin perustuvasta piirtämisestä on se etu, että voimme muuttaa mallia ja pitää piirtokoodin muuttumattomana. private Ellipse2D ellipsi; private void paivita() { this.ellipsi.x -= 2; g2d.draw(this.ellipsi); Todellisissa ohjelmissa piirrettävien asioiden mallit kannattaa yleensä erottaa omaan luokkaansa.
Päivityssykli paintcomponent-metodissa kerroimme Swingille, miten haluamme paneelimme piirrettävän. Emme ottaneet kantaa siihen, kuinka usein piirtäminen tapahtuu. public void actionperformed (ActionEvent e) { paivita(); repaint(); Swing ei automaattisesti päivitä komponenttien ulkoasua sen muuttuessa, vaan siitä on komponentin tekijän huolehdittava itse. Kutsumalla komponentin repaint()-metodia pyydämme Swingiä piirtämään komponentin uudestaan. Swing tottelee kun ehtii.
Piirtopaneeli 2.0 public Piirtopaneeli() { Timer ajastin = new Timer(10, new ActionListener() { public void actionperformed(actionevent e) { Piirtopaneeli.this.paivita(); Piirtopaneeli.this.repaint(); ); ajastin.start(); private void paivita() { ellipsi.x -= 2; if (ellipsi.x < -ellipsi.width) { ellipsi.x = getwidth();
Animaatio kuvat = new ArrayList<Image>(); int i = 1; while (new File("frame-" + i + ".png").exists()) { try { kuvat.add(imageio.read(new File("frame-" + i + ".png"))); catch (IOException e) { e.printstacktrace(); System.exit(1); i++; Mitä tässä tapahtuu?
Piirtopaneeli 3.0 private int indeksi; private void paivita() {... if (indeksi < kuvat.size()-1) { indeksi++; else { indeksi = 0; protected void paintcomponent(graphics g) {... g2d.drawimage(kuvat.get(indeksi), 600, 50, null);
Optimoinnin säännöt 1. Älä tee sitä! Koodista tulee helposti sekavaa 2. Älä tee sitä vielä! Optimoi vasta kun koodi toimii
Jos on pakko... 1. Optimoi algoritmia (älä syntaksia) Piirrä vain tarvittaessa Esim. dirty rectangles 2. Älä luule optimoinnin toimivan Testaa, paljonko aikaa koodin suorittamiseen kuluu
Kokeilkaa itse!