====== Laboratorium 10: rysujemy choinkę ====== Użyjemy biblioteki graficznej Swing, a dokładniej klasy potomnej ''JPanel''. Umieść w klasie głównej poniższą funkcję ''main()'' public static void main(String[] args) { // write your code here JFrame frame = new JFrame("Choinka"); frame.setContentPane(new DrawPanel()); frame.setSize(1000, 700); frame.setLocationRelativeTo(null); frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); frame.setResizable(true); frame.setVisible(true); } ===== DrawPanel ===== ''DrawPanel()'' to klasa, której na razie brakuje. Utwórz ją w projekcie i dodaj funkcję ''paint(Graphics g)'' z przykładowym kodem wypisującym tekst. public class DrawPanel extends JPanel { public void paintComponent(Graphics g){ g.setFont(new Font("Helvetica", Font.BOLD, 18)); g.drawString("Hello World", 20, 20); System.out.println("painting"); } } Zaobserwuj, kiedy na konsoli wypisywane jest ''painting''. ''Graphics'' to kontekst graficzny. Obiekt przechowuje informacje o bieżących atrybutach rysowania (font, kolor) oraz pozwala wywołać funkcje umożliwiające rysowanie wektorów oraz obrazów. Wypróbuj kilka funkcji do rysowania. Na przykład == Rysowanie linii == g.drawLine(10,10,100,100); == Rysowanie elips == g.setColor(Color.yellow); g.fillOval(100,101,30,30); g.setColor(Color.black); g.drawOval(100,101,30,30); == Rysowanie wieloboków == int x[]={286,253,223,200,148,119,69,45,0}; int y[]={0,101,89,108,79,95,66,80,56}; g.fillPolygon(x,y,x.length); == Rysowanie obrazków == Jeżeli chciałbyś wyświetlić obrazek, należy wcześniej go załadować, np. przechowywać jako atrybut klasy. (Nie należy ładować go w funkcji ''paint''). Image img = Toolkit.getDefaultToolkit().getImage("bird1.jpg"), a następnie wyświetlić w funkcji paint() g.drawImage(img,0,0,getWidth(),getHeight(),this); ===== Graphics2D ===== ''Graphics2D'' jest rozszerzoną wersją kontekstu graficznego pozwalającą na bardziej zaawansowane operacje. Aby uzyskać dostęp do obiektu ''Graphics2D'' wystarczy rzutowanie. public void paintComponent(Graphics g){ Graphics2D g2d= (Graphics2D)g; } Ważną cechą ''Graphics2D'' jest możliwość transformacji układu współrzędnych odpowiadających powinowactwom (~ klasy I LO), czyli: *przesuniecia *skalowanie *rotacje Poniższy kod rysuje 12 linii obracając je o 30 stopni // zachowaj macierz przekształcenia AffineTransform mat = g2d.getTransform(); // przesuń początek układu g2d.translate(100,100); // zastosuj skalowanie g2d.scale(.2,.2); // narysuj linie for(int i=0;i<12;i++){ g2d.drawLine(0,0,100,100); g2d.rotate(2*Math.PI/12); } //oddtwórz poprzednie ustawienia transformacji układu współrzędnych g2d.setTransform(mat); Analogicznie możesz obrócić tekst podczas rysowania... g2d.translate(200,200); // zastosuj skalowanie g2d.scale(.2,.2); g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); Font font = new Font("Serif", Font.PLAIN, 96); g2d.setFont(font); for(int i=0;i<12;i++){ g2d.drawString("Happy new year",150,0); g2d.rotate(2*Math.PI/12); } Możesz ustawić atrybuty linii.... // zachowaj macierz przekształcenia AffineTransform mat = g2d.getTransform(); // przesuń początek układu g2d.translate(200,200); // zastosuj skalowanie g2d.scale(.2,.2); g2d.setStroke(new BasicStroke(50, CAP_ROUND,JOIN_MITER)); for(int i=0;i<12;i++){ //g2d.drawString("Happy new year",150,0); g2d.drawLine(0,0,100,100); g2d.rotate(2*Math.PI/12); } //oddtwórz poprzednie ustawienia transformacji układu współrzędnych g2d.setTransform(mat); Możesz też użyć gradientowego wypenienia dla wieloboków Graphics2D g2d= (Graphics2D)g; AffineTransform mat = g2d.getTransform(); GradientPaint grad = new GradientPaint(0,0,new Color(0,255,0),0,100, new Color(0,10,0)); g2d.setPaint(grad); g2d.translate(0,50); g2d.scale(0.7,0.5); int x[]={286,286,223,200,148,119,69,45,0}; int y[]={0,131,89,108,79,95,66,80,56}; g2d.fillPolygon(x,y,x.length); g2d.translate(670,0); g2d.scale(-1,1); g2d.fillPolygon(x,y,x.length); g2d.setTransform(mat); ==== Tło ==== Możesz ustawić tło wołając metodę ''setBackground()'' klasy ''JPanel'' Na przykład DrawPanel(){ setBackground(new Color(0,0,50)); // setOpaque(true); } Nie zapomnij na początku ''paintComponent()'' wywołać metodę ''paintComponent()'' nadklasy ===== Rysowanie choinki ===== W zasadzie można narysować choinkę składając ją z powtarzalnych elementów: gałęzie, ozdoby, świeczki, itp. Może być to jedna długa funkcja, w której wołany jest np. kod do rysowania odpowiednio przesuniętych i przeskalowanych gałęzi, ozdób, lampek itp. Zamiast tego, zdefiniujemy klasy elementów składowych ==== Klasa bazowa (interfejs bazowy) ==== W zasadzie powinien nazywać sie ''Shape'', ale taki już jest [[https://docs.oracle.com/javase/8/docs/api/java/awt/Shape.html]] Nazwiemy go ''XmasShape'' public interface XmasShape { /** * Przesuwa poczatek układu w zadane miejsce, skaluje, jeśli trzeba obraca * @param g2d Graphics2D - kontekst graficzny */ void transform(Graphics2D g2d); /** * Zawiera kod, który rysuje elementy * @param g2d Graphics2D - kontekst graficzny */ void render(Graphics2D g2d); /** * Standardowa implementacja metody * @param g2d */ default void draw(Graphics2D g2d){ // Get the current transform AffineTransform saveAT = g2d.getTransform(); // Perform transformation transform(g2d); // Render render(g2d); // Restore original transform g2d.setTransform(saveAT); } } ==== Napisz klasę Bubble ==== To ma być jedna z ozdób public class Bubble implements XmasShape { int x; int y; double scale; Color lineColor; Color fillColor; @Override public void render(Graphics2D g2d) { // ustaw kolor wypełnienia g2d.fillOval(0,0,100,100); // ustaw kolor obramowania g2d.drawOval(0,0,100,100); } @Override public void transform(Graphics2D g2d) { g2d.translate(x,y); g2d.scale(scale,scale); } } Uwagi: *obiekt zawsze jest rysowany tak samo (funkcja ''render'') *zmienia się położenie i skala obiektu; jest ona interpretowana w funkcji ''transform'' ==== Refaktoryzacja DrawPanel ==== Dodaj atrybut List shapes = new ArrayList<>(); Zmień funkcję ''paintComponent()'' na następującą: public void paintComponent(Graphics g){ super.paintComponent(g); for(XmasShape s:shapes){ s.draw((Graphics2D)g); } } === Dodaj obiekty === Dodaj kilka obiektów klasy ''Bubble'' i sprawdź, czy wyświetlane są zgodnie z oczekiwaniami. Napisz osobną funkcje do dodawania obiektów w ''DrawPanel'' i wywołaj ją w konstruktorze lub funkcji ''main()''. Nie dodawaj obiektów w ''paintCpmponent()'' ==== Kolejne klasy ==== *Dodaj klasę ''Branch'' - zielona gałąź drzewa *Możesz utworzyć klasę ''Tree'' zawierającą listę ''XmasShape'' i złożyć gotowe drzewko z gałęzi *Dodaj klasę ''Light'' *Możesz dodać gwiazdki i inne ozdoby... Za każdym razem: * określ, jakie atrybuty są potrzebne, aby przeprowadzić transformację układu współrzędnych * napisz funkcję ''transform()'' * napisz kod rysujący element -- ''render()'' ===== Proszę o umieszczenie na git zrzutów ekranu choinek =====