Program do grafiki wektorowej

0

Witam.

Chciałbym napisać (jak w temacie) prosty program do grafiki wektorowej (tworzenie prostych figur koła, kwadraty itd. przesuwanie zaznaczonych figur, zapisywanie do pliku np. svg, odczyt) w języku JAVA. Co polecacie, czy zaczynać od Apache Batik, czy może jest coś łatwiejszego?
Jeśli Batik to czy moglibyście mi polecić jakieś dobre książki, ewentualnie tutoriale na początek by szybko załapać.

Pozdrawiam.

0

Do zrobienia czegoś takiego to nie potrzeba żadnych specjalnych technologii ani bibliotek przecież. Chyba faktycznie tylko do samego zapisywania plików jeśli koniecznie chcesz SVG. Bo do takiego XMLa mógłbyś pisać bez tego.
Nie wiem do czego chcesz książkę albo tutorial, skoro to jest zabawa na kilkaset linijek kodu ;)
Malować możesz po panelu. Masz drawOval, drawLine, drawRectangle. Potrzebujesz tylko na evencie puszczenia guzika myszki zrobić sobie logikę tworzenia obiektów na scenie (tzn jak kończysz rysować kółko to zapisujesz je w kolekcji obiektów na scenie).

0

Wiem jak tworzyć takie programy do grafiki rastrowej i z tego co napisałeś rozumiem że nie potrzeba jakiś specjalnych paneli obsługujących pewne wektorowe funkcje, a jedynie program w stylu grafiki rastrowej który by wszystko zapisywał do pliku jako XML. Tylko że w jaki sposób później otworzyć taki stworzony przeze mnie plik by wszystkie elementy były oddzielnie przesuwane a nie traktowane jako cały obraz jako np. bitmap? A jeśli tak to zostanie zrobione, to przecież po stworzeniu figury np. koła chcąc je po jakimś czasie przekształcić np. powiększyć to bardzo uwydatnią mi się piksele tego obiektu (jak w programach do grafiki rastrowej).

0

Wiesz co to jest programowanie obiektowe? To teraz musisz to wykorzystać. Potraktuj koła, kwadraty stworzone przez użytkownika jako obiekty, trzymaj je gdzieś w pamięci podczas działania programu a potem zapisuj. Najłatwiej będzie ci stworzyć jakiś swój prosty format zapisu. Możliwość wczytania takiego pliku polega na inicjalizacji np listy obiektów widocznych na ekranie tymi wczytanymi z pliku. No a potem musisz już je tylko wyrysować.

0

@szewcz nie bardzo cię rozumiem. Zrób sobie klasę Shape, z niej dziedzicz np. Rectangle. Malując prostokąt tworzysz sobie obiekt Rectangle i dorzucasz do kolekcji obiektów na scenie. Taki obiekt ma na przykład pozycje lewego górnego roku plus X i Y. W czym problem?

0

Więc w jaki sposób zapisać stworzony obraz jako plik wektorowy bym mógł go później otworzyć?

0

Nie rozumiem pytania. Masz kolekcje obiektów. Serializujesz ją do takiej postaci do jakiej chcesz. Potem przy wczytywaniu pliku musisz wczytać tą kolekcję i odrysować wszystkie wczytane obiekty. Najprościej żeby to klasa Shape miała metode odrysujSie() która przyjmuje kontekst graficzny gdzie ma się narysować a klasy implementujące niech same się martwią tym jak sie odrysować. Na przykład klasa Circle będzie w swojej metodzie odrysujSie() robiła drawOval() itd.

0

Teraz ja do końca nie rozumiem ;p więc miałbym serializować listę obiektów do pliku np. pdf?
Chciałbym po prostu zapisać ten plik w formacie wektorowym (svg, pdf, eps), a następnie go otworzyć w przeglądarce by podczas skalowania nie tracił na jakości. Później ewentualnie go otworzyć w moim programie.

2

Słabo mi sie robi jak czytam twoje posty bo nie poświęciłeś nawet 3 minut na doczytanie co to w ogóle są pliki SVG i na czym polega grafika wektorowa. Plik SVG to jest zwykły XML o pewnej znanej składni. Otwórz sobie notatnikiem na przykład http://upload.wikimedia.org/wikipedia/commons/1/12/Пример_чертежа_в_SVG_формате.svg i zobaczysz o co chodzi. Są biblioteki które umożliwiają tworzenie takich plików wiec możesz albo uzywać od razy typów z takiej biblioteki przy generowaniu obiektów na scenie albo napisać w swoich klasach odpowiednie konwersje, to jest generalnie szczegół.
Moja rada: zamiast gdybać i wymyślać na siłę jakieś problemy to siądź i to zwyczajnie napisz. To jest program na 2 wieczory dla średniego studenta...

0

A więc czy to może tak wyglądać? Czy proponujecie jakieś lepsze rozwiązanie?


package programdografikiwektorowej;

import java.awt.EventQueue;
import javax.swing.JFrame;

public class ProgramDoGrafikiWektorowej {

    public static void main(String[] args) {
           EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new OknoGlowne();
                //frame.setLayout(new BoxLayout(frame, BoxLayout.PAGE_AXIS));
                frame.setLocationRelativeTo(null);
                frame.setTitle("XMLWriteTest");
                frame.setResizable(false);
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setVisible(true);
            }
        });

    }
}
 
 

package programdografikiwektorowej;

import java.awt.*;
import javax.swing.*;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
import java.beans.EventHandler;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.ArrayList;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;

public class OknoGlowne extends JFrame{
    
    public int szerokoscPlotna = 700;
    public int wysokoscPlotna = 600;
    public int Xpocz, Ypocz, Xkon, Ykon;
    JMenuBar menuBar;
    JMenu menu;
    JMenuItem menuItemZapisz;
    private JFileChooser chooser;
    public Rectangle comp2;
    public Ellipse comp3;
    public Line comp1;
    
    //enum Tool {Line, Rectangle, Ellipse}
    //Tool wybraneNarzedzie;
    
    
    public OknoGlowne()
    {
        super("Program do grafiki wektorowej");
        setSize(600, 600);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        
        comp1 = new Line();
        add(comp1); 
        comp2 = new Rectangle();
        add(comp2); 
        comp3 = new Ellipse();
        add(comp3);
        
        menuBar = new JMenuBar();
        menu = new JMenu("File");
        menuBar.add(menu);
        menuItemZapisz = new JMenuItem("Zapisz");
        menu.add(menuItemZapisz);
        menuItemZapisz.addActionListener(EventHandler.create(ActionListener.class, this,"saveDocument"));
        
        chooser = new JFileChooser();
        
        Box lewyBox = Box.createVerticalBox();
        ButtonGroup radioGroup = new ButtonGroup();
        
        final JRadioButton rysujLinieRadioB = new JRadioButton("Rysuj linię");
        final JRadioButton rysujKwadratRadioB = new JRadioButton("Rysuj kwadrat");
        final JRadioButton rysujKoloRadioB = new JRadioButton("Rysuj koło");
        
        radioGroup.add(rysujLinieRadioB);
        radioGroup.add(rysujKwadratRadioB);
        radioGroup.add(rysujKoloRadioB);
        rysujLinieRadioB.setSelected(true);
        
        lewyBox.add(rysujLinieRadioB);
        lewyBox.add(rysujKwadratRadioB);
        lewyBox.add(rysujKoloRadioB);
        
        Box prawyBox = Box.createVerticalBox();
        JPanel panelRysowania=new JPanel() {
            @Override
        public void paint(Graphics g) {
            super.paint(g);
            Graphics2D g2 = (Graphics2D) g;
            
            g2.setColor(Color.BLACK);
            for (int i = 0; i < Line.lines.size(); i++)
            {
                g2.draw(Line.lines.get(i));
            } 
            for (int i = 0; i < Rectangle.rects.size(); i++)
            {
                g2.fill(Rectangle.rects.get(i));
            } 
            for (int i = 0; i < Ellipse.ellipse.size(); i++)
            {
                g2.fill(Ellipse.ellipse.get(i));
            }
        }
        };
        
        panelRysowania.setBackground(Color.white);
        panelRysowania.setPreferredSize(new Dimension(szerokoscPlotna, wysokoscPlotna));
        prawyBox.add(panelRysowania);
        
        Box polaczenieLP = Box.createHorizontalBox();
        polaczenieLP.add(lewyBox);
        polaczenieLP.add(prawyBox);
        
        Box glownyBox = Box.createVerticalBox();
        glownyBox.add(menuBar);
        glownyBox.add(polaczenieLP);
        
        
        panelRysowania.addMouseListener(new MouseAdapter() {
            @Override
            public void mousePressed(MouseEvent e) {
                Xpocz=e.getX();
                Ypocz=e.getY();
            }
        });
        
        panelRysowania.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseReleased(MouseEvent e) {
                if(rysujLinieRadioB.isSelected()==true)
                {
                    Xkon=e.getX();
                    Ykon=e.getY();
                    Line.lines.add(new Line2D.Double(Xpocz,Ypocz,Xkon,Ykon));
                }
                else if(rysujKwadratRadioB.isSelected()==true)
                {
                    Xkon=e.getX()-Xpocz;
                    Ykon=e.getY()-Ypocz;
                    Rectangle.rects.add(new Rectangle2D.Double(Xpocz,Ypocz,Xkon,Ykon));
                }
                else if(rysujKoloRadioB.isSelected()==true) 
                {
                    Xkon=e.getX()-Xpocz;
                    Ykon=e.getY()-Ypocz;
                    Ellipse.ellipse.add(new Ellipse2D.Double(Xpocz,Ypocz,Xkon,Ykon));
                }
                
                repaint();
            }
        });
        
        Container content = this.getContentPane();
        content.setLayout(new BorderLayout());
        content.add(menuBar, BorderLayout.PAGE_START);
        content.add(glownyBox, BorderLayout.CENTER);
        this.pack();

        setVisible(true);
    } 
    
    public void saveDocument() throws TransformerException, IOException
    {
        if (chooser.showSaveDialog(this) != JFileChooser.APPROVE_OPTION) return;
        File file = chooser.getSelectedFile();
        Document doc = comp1.buildDocument();
        Transformer t = TransformerFactory.newInstance().newTransformer();
        t.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM,
        "http://www.w3.org/TR/2000/CR-SVG-20000802/DTD/svg-20000802.dtd");
        t.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC, "-//W3C//DTD SVG 20000802//EN");
        t.setOutputProperty(OutputKeys.INDENT, "yes");
        t.setOutputProperty(OutputKeys.METHOD, "xml");
        t.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
        t.transform(new DOMSource(doc), new StreamResult(Files.newOutputStream(file.toPath())));
    }
    
}
 

package programdografikiwektorowej;

import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import javax.swing.JComponent;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

public class Shape extends JComponent {
    
    public static DocumentBuilder builder;
    public int szerokoscPlotna = 700;
    public int wysokoscPlotna = 600;
    
    public Document buildDocument()
    {
        String namespace = "http://www.w3.org/2000/svg";
        Document dokument = builder.newDocument();
        Element svgElement = dokument.createElementNS(namespace, "svg");
        dokument.appendChild(svgElement);
        svgElement.setAttribute("width", "" + szerokoscPlotna );
        svgElement.setAttribute("height", "" + wysokoscPlotna);
        for (int i = 0; i <Line.lines.size(); i++)
        {
            Line2D e=Line.lines.get(i);
            Element lineElement = dokument.createElementNS(namespace, "line");
            lineElement.setAttribute("x1", "" + e.getX1());
            lineElement.setAttribute("y1", "" + e.getY1() );
            lineElement.setAttribute("x2", "" + e.getX2());
            lineElement.setAttribute("y2", "" + e.getY2());
            lineElement.setAttribute("style", "stroke:black ;stroke-width:1" );
            lineElement.setAttribute("fill", "#000000");
            svgElement.appendChild(lineElement);
        }
        for (int i = 0; i < Rectangle.rects.size(); i++)
        {
            Rectangle2D r = Rectangle.rects.get(i);
            Element rectElement = dokument.createElementNS(namespace, "rect");
            rectElement.setAttribute("x", "" + r.getX());
            rectElement.setAttribute("y", "" + r.getY());
            rectElement.setAttribute("width", "" + r.getWidth());
            rectElement.setAttribute("height", "" + r.getHeight());
            rectElement.setAttribute("fill", "#000000");
            svgElement.appendChild(rectElement);
        }
        for (int i = 0; i < Ellipse.ellipse.size(); i++)
        {
            Ellipse2D e=Ellipse.ellipse.get(i);
            Element ellipseElement = dokument.createElementNS(namespace, "ellipse");
            ellipseElement.setAttribute("cx", "" + (e.getX()+e.getWidth()/2) );
            ellipseElement.setAttribute("cy", "" + (e.getY()+e.getHeight()/2) );
            ellipseElement.setAttribute("rx", "" + e.getWidth()/2);
            ellipseElement.setAttribute("ry", "" + e.getHeight()/2);
            ellipseElement.setAttribute("fill", "#000000");
            svgElement.appendChild(ellipseElement);
        }
        
        return dokument;
    }
}


 class Line extends Shape{
    
    public static java.util.List<Line2D> lines;
    
    public Line( ) {
        lines = new ArrayList<>();
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        factory.setNamespaceAware(true);
        try
        {
            Shape.builder = factory.newDocumentBuilder();
        }
            catch (ParserConfigurationException e)
        {
            e.printStackTrace();
        }
    }   
}
class Rectangle extends Shape{

public static java.util.List<Rectangle2D> rects;
    
    public Rectangle( ){
        rects = new ArrayList<>();
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        factory.setNamespaceAware(true);
        try
        {
            Shape.builder = factory.newDocumentBuilder();
        }
            catch (ParserConfigurationException e)
        {
            e.printStackTrace();
        }
    }
}
class Ellipse extends Shape{
    
    public static java.util.List<Ellipse2D> ellipse;
    
    public Ellipse( ){
        ellipse = new ArrayList<>();
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        factory.setNamespaceAware(true);
        try
        {
            Shape.builder = factory.newDocumentBuilder();
        }
            catch (ParserConfigurationException e)
        {
            e.printStackTrace();
        }
    }   
} 
1

Dobrze że już coś napisałeś, ale niewiele tu jest poprawnie. Po kolei:

  1. W klasie głównej zrób JEDNĄ kolekcję obiektów Shape np. List<Shape> i tyle. Koniec, kropka.
  2. Klasy pochodne tzn Line czy Rectangle NIE zawierają żadnej statycznej listy. One mają służyć tylko i wyłącznie do operacji związanych z konkretnymi kształtami. Niech każda z tych klas ma metodę drawYourself(Graphics g) w której będzie wykonywać rysowanie. Więc na przykład dla Line to będzie
public void drawYourself(Graphics g){
  g.draw(line);
}

Gdzie line to jest Line2D wrappowane przez naszą klasę. Dzięki temu zamiast 3 dziwnych pętli odmalowanie sceny to będzie jedna pętla która na wszystkich Shape wywoła drawYourself().
3. Niech każda z tych klas wie jak ma generować dla siebie XMLa. Nie wpychaj tego do jakiejś metody z d**y w klasie Shape. Niech prostokąt sam generuje swojego xmla. Niech będzie to metoda np. public Element getXML(). Dla Line to będzie na przykład

public Element getXML(Document doc){
            Element lineElement = doc.createElementNS(namespace, "line");
            lineElement.setAttribute("x1", "" + getX1());
            lineElement.setAttribute("y1", "" + getY1() );
            lineElement.setAttribute("x2", "" + getX2());
            lineElement.setAttribute("y2", "" + getY2());
            lineElement.setAttribute("style", "stroke:black ;stroke-width:1" );
            lineElement.setAttribute("fill", "#000000");
            return lineElement;
}

Dzięki temu znów generacja xmla to będzie jedna ładna pętla po wszystkich Shape w liście a nie 3 dziwne pętle w miejscu z d**y.
4. Twoje mouseReleased to tragedia. Nie dało się najpierw pobrać tych x i y a potem tworzyć obiektu? Czemu skopiowałeś ten kod tyle razy? Poza tym ja bym się zastanowił czy nie da się jednak jakoś sensowniej tego zrobić niż drabinką ifów. Jak będziesz miał 100 rodzajów obiektów to też tak zrobisz?
5. Niech twoje klasy rozszerzające Shape będą wrapperami ma te standardowe javowe klasy, tzn twój obiekt Line w kontruktorze niech przyjmuje Line2D itd

0
  1. Moja klasa Shape wygląda następująco.
 public class Shape  {
    
    public List<Shape> listaKsztaltow=new ArrayList<Shape>();

    public void drawYourself(Graphics2D g2) 
    {
    }

    public Element getXML(Document dokument) {
        return null;
    }   
}
    1. oraz 5. Czy lepiej by było gdybym coś tu poprawił? Poniżej klasa Line reszta jest zbudowana analogicznie.
 public class Line extends Shape{
    
    public Line2D line;
    public static String namespace = "http://www.w3.org/2000/svg";
    
    public Line(Line2D line2) {
        line=new Line2D.Double(line2.getX1(),line2.getY1(),line2.getX2(),line2.getY2());
    }
    
    public Element getXML(Document doc){
        Element lineElement = doc.createElementNS(namespace, "line");
        lineElement.setAttribute("x1", "" + line.getX1());
        lineElement.setAttribute("y1", "" + line.getY1() );
        lineElement.setAttribute("x2", "" + line.getX2());
        lineElement.setAttribute("y2", "" + line.getY2());
        lineElement.setAttribute("style", "stroke:black ;stroke-width:1" );
        lineElement.setAttribute("fill", "#000000");
        return lineElement;
    }
    
    public void drawYourself(Graphics2D g)
    {
        g.draw(line);
    }
} 
  1. Nie wiem czy lepiej ale zmieniłem MouseReleased na swicha po enum Tools, który zmienia się w zależności, w który radioButton się kliknie.
 switch (wybraneNarzedzie)
                {
                    case Line:
                        line2d=new Line2D.Double(Xpocz,Ypocz,Xkon,Ykon);
                        line=new Line(line2d);
                        ksztalt.listaKsztaltow.add(line);
                        break;
                        
                    case Rectangle: 
                    .
                    .
                    .

A to kod do wpisania do pliku wrzuciłem to do funkcji saveDocument

        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        factory.setNamespaceAware(true);
        try
        {
            builder = factory.newDocumentBuilder();
        }
            catch (ParserConfigurationException e)
        {
            e.printStackTrace();
        }
        Document dokument = builder.newDocument();
        Element svgElement = dokument.createElementNS(Line.namespace, "svg");
        dokument.appendChild(svgElement);
        svgElement.setAttribute("width", "" + szerokoscPlotna );
        svgElement.setAttribute("height", "" + wysokoscPlotna);
        for (int i = 0; i <ksztalt.listaKsztaltow.size(); i++)
        {
            svgElement.appendChild(ksztalt.listaKsztaltow.get(i).getXML(dokument));
        }

Chciałbym jeszcze wczytać plik SVG do mojego programu w jaki sposób miałbym to zrobić? Czy trzeba to wykonać za pomocą DOM XML Parsera wczytując wszystkie wartości z pliku i przyporządkowując je odpowiednim figurom na liście? Czy jest coś innego z czego mógłbym skorzystać?

1
  • lekcja na dziś: abstract zamiast pustych metod ;)
  • OMG! Lista kształtów ma być polem klasy gdzie masz okno co najwyżej. Zapomnij o istnieniu słowa static!
  • namespace może być przecież w Shape jako protected!
  • pola klasy private!
  • ten konstruktor to jakis WTF, skoro dostajesz obiekt Line2D to go przypisz do tego swojego pola i tyle. po co robisz nowy? o_O
  1. Ja bym zrobił inaczej. Zrobiłbym mapę która mapuje enum na klasa_dziedzicząca_z_shape ( http://docs.oracle.com/javase/8/docs/api/java/util/EnumMap.html ). Zmieniłbym wtedy kontruktor tych Shape na taki który przyjmuje x1,x2,y1,y2 i potem robił w tym mouse released:
klasa = mapa.get(wybraneNarzedzie);
Shape obiekt = klasa.newInstance(x1,x2,y1,y2);
listaObiektówNaScenie.add(obiekt);

i voila. Żadnych ifów ani switchy!

Ech chłopie, co to jest? Java 1.1? O foreach słyszał?

for(Shape s : listaObiektówNaScenie){
    svgElement.appendChild(s.getXML(dokument));
}

Wczytanie jest teraz trywialne. Wczytaj svg tą swoją biblioteką a potem utwórz te swoje obiekty i wrzuć do listy obiektów na scenie i voila.

0

Jeśli chodzi o wczytywanie. To kiedy już wczytałem sam plik

File xmlFile = new File("E:/aaa.xml");
            DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
            Document doc = dBuilder.parse(xmlFile);

            doc.getDocumentElement().normalize();

to próbując dostać się do atrybutów moja funkcja dla klasy Line() wygląda tak

 public Shape pobierzDaneZXML(Document document, String nazwa, Line line)
    {
        double x1,x2,y1,y2;
        x1=Double.parseDouble(document.getElementsByTagName(nazwa).item(0).getAttributes().getNamedItem("x1").getNodeValue());
        x2=Double.parseDouble(document.getElementsByTagName(nazwa).item(0).getAttributes().getNamedItem("x2").getNodeValue());
        y1=Double.parseDouble(document.getElementsByTagName(nazwa).item(0).getAttributes().getNamedItem("y1").getNodeValue());
        y2=Double.parseDouble(document.getElementsByTagName(nazwa).item(0).getAttributes().getNamedItem("y2").getNodeValue());
        Line2D line2d=new Line2D.Double(x1,y1,x2,y2);
        line=new Line(line2d);
        
        return line;
    }

Tu moje pytanie dlaczego to jest źle?

0
  1. Mam zgadywać jak ten xml wygląda? o_O
  2. Rozumiem że nie dało się wyciągnąć do zmiennej document.getElementsByTagName(nazwa).item(0).getAttributes() tylko trzeba kopiować to 100 razy?
  3. Nie będę odpowiadał na twoje posty o ile nie zastosujesz się do 3 zasad raportowania błędów:
  • co zrobiłeś
  • czego sie spodziewałeś
  • co się faktycznie stało
    Bo napisałeś dlaczego to jest źle nie dając żadnej informacji o problemie. Kod sie nie kompiluje? Wysypało się? Nie pobrało danych? Sprawdziłeś pod debugerem ten kod?

Poza tym nie bardzo ten kod rozumiem. Ty chyba chcesz wczytać wszystkie kształty z pliku a nie tylko jeden? o_O

0
  1. XML z którego korzystam
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg height="600" width="700" xmlns="http://www.w3.org/2000/svg">
  <line fill="#000000" style="stroke:black ;stroke-width:1" x1="215.0" x2="215.0" y1="85.0" y2="85.0"/>
  <line fill="#000000" style="stroke:black ;stroke-width:1" x1="161.0" x2="299.0" y1="201.0" y2="339.0"/>
</svg>
  
  1. Ale jak zrobię tak jak napisałeś to mam coś takiego jako string com.sun.org.apache.xerces.internal.dom.AttributeMap@1edd9b3 a inaczej to nie wiem jak miałby program wiedzieć że moje <line> ma atrybuty x1 x2 y1 y2, a <rect> atrybuty x y width height

  2. Zrobiłem niewiele, funkcja abstrakcyjna pobierzDaneZXML() w Shape i nadpisywanie tej funkcji w Line (ta którą wstawiłem wcześniej), Rectangle i Ellipse. Problem w tym, że nie wiem w jaki sposób miałbym dodawać kolejne kształty do nowej listy na obiekty ładowane z pliku. Niby tą funkcję mam od tworzenia kształtu w Line(), ale nie mogę dodać stworzonego Shape do listy bo krzyczy że metoda pobierzDaneZXML() powinna być w klasie OknoGlowne gzie mam wunkcję wczytującą

póki co moja funkcja wczytująca

    public void openDocument()
    {
        try
        {
            File xmlFile = new File("E:/aaa.xml");
            DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
            Document doc = dBuilder.parse(xmlFile);

            doc.getDocumentElement().normalize();

            listaKsztaltow2.add(pobierzDaneZXML(doc,"line",line));    ////// tu jest błąd 
            
        }
        catch(Exception e) {
            e.printStackTrace();
        }
        repaint();
    }

sory że tak niejasno

0
  1. Słabo mi się robi czasem jak czytam twoje odpowiedzi. Chodziło mi tylko o to zeby zrobić:
attrMap = document.getElementsByTagName(nazwa).item(0).getAttributes();
x1=Double.parseDouble(attrMap.getNamedItem("x1").getNodeValue());
x2=Double.parseDouble(attrMap.getNamedItem("x2").getNodeValue());
y1=Double.parseDouble(attrMap.getNamedItem("y1").getNodeValue());
y2=Double.parseDouble(attrMap.getNamedItem("y2").getNodeValue());

Bo sie to łatwiej czyta...
3. OMG ten kod po prostu nie ma sensu. Myśl nad tym co robisz. I gdzie upychasz kod...

//
List<Shape> fromFile = readShapesFromFile(doc);
listaKsztaltow.addAll(fromFile);
//
List<Shape> readShapesFromFile(Document doc){
    List<Shape> fromFile = new ArrayList<Shape>();
    Element svg = getElementsByTagName("svg").item(0);
    NodesList shapes = svg.getChildNodes();
    for(int i=0;i<shapes.length();i++){
        Node shape = shapes.item(i);
        Shape parsedShape = createShapeFromXML(shape);
        fromFile.add(parsedShape);
    }
    return fromFile;
}

W tej funkcji createShapeFromXML nie chce mi sie pisać, ale generalnie jest trywialna:

  • wczytujesz nazwę tagu i na tej podstawie wybierasz kontruktor (identycznie jak wcześniej na podstawie tej mapy enumów!). Warto tu sprawdzić czy obsługujemy dany typ kształtu ;)
  • wczytujesz te swoje x1,x2,x3,x4
  • tworzysz instancje danego shape identycznie jak wcześniej tylko tym razem nie pobierasz x1,x2,x3,x4 z tego klikania tylko z xmla

I voila.

0

Nie wiem co z tym zrobić. Jeśli chodzi o tą funkcję co wstawiłeś w tej linii miałem błąd

Element svg = getElementsByTagName("svg").item(0);

więc zmieniłem (nie jestem pewien czy poprawnie)

Element svg = (Element)doc.getElementsByTagName("svg").item(0);

i moja funkcja do tworzenia kształtu na razie chcę żeby działało dla samych linii

    private Shape createShapeFromXML(Node shape, Document doc) 
    {
        double x1,x2,y1,y2;
        NamedNodeMap attrMap;
        Line linia;
        String nazwa=shape.getNodeName();
        
            attrMap = doc.getElementsByTagName(nazwa).item(0).getAttributes();
            x1=Double.parseDouble(attrMap.getNamedItem("x1").getNodeValue());
            x2=Double.parseDouble(attrMap.getNamedItem("x2").getNodeValue());
            y1=Double.parseDouble(attrMap.getNamedItem("y1").getNodeValue());
            y2=Double.parseDouble(attrMap.getNamedItem("y2").getNodeValue());
            Line2D line2dz=new Line2D.Double(x1,y1,x2,y2);
            linia=new Line(line2dz);
        
        return linia;
    }

Chodzi o to, że w taki sposób wczytuje mi tylko jedną pierwszą linię, a rozumiem, że ta petla

for(int i=0;i<shapes.getLength();i++){
            Node shape = shapes.item(i);
            Shape parsedShape = createShapeFromXML(shape,doc);
            fromFile.add(parsedShape);
        }

działa po wszystkich elementach w pliku, a wyświetla mi jedynie tylko pierwszy kształt i to tylko wtedy gdy wpiszę ręcznie "line" do attrMap = doc.getElementsByTagName(nazwa).item(0).getAttributes();, bo wpisując tą zmienną nazwa wywala mi java.lang.NullPointerException. O co chodzi?

0

Brak mi do ciebie słów.

  1. Nie pisz bezmyślnie! Źle popatrzyłem w dokumentacje a pisałem ten kod z palca. Wystarczy ci tam Node, nie musi być Element. Jesli będziesz kopiował kod bez zrozumienia to nic z tego nie będzie.
  2. Twoja funkcja jest zwyczajnie błędna i do niczego sie nie nadaje.
  3. Nie rozumiem tego co napisałeś na koniec. Póki nie nauczysz się pisać kodu ze zrozumieniem i używać debuggera to nic z tego nie będzie. Kod pisałem z palca więc może sie nie kompilować albo nie działać. Chodziło mi przekazanie idei a nie gotowca do skopiowania. Jakbyś podał linka do repozytorium z tym kodem to może bym go ściągnął i zerknął, a tak?
0

https://github.com/Pharisaeus/vectorgraphics będzie tu wisieć bardzo krótko żeby mi wstydu nie przynosiło więc szybko sobie sklonuj :P
Wprowadziłem trochę poprawek żeby to miało ręce i nogi. Idealnie nie jest, ale tragedii nie ma. Nie rozumiem tylko po co się tyle naprodukowałem w tym temacie skoro wszystkie moje rady miałeś w głębokim poważaniu...

0

Sory że piszę znowu, ale chciałbym jeszcze dodać jeszcze jedną figurę czyli kwadrat lecz jako same boki a nie wypełniony. Chodzi o to że program rysuje mi ten kwadrat za pomocą klasy RectangleDraw i zapisuje w pliku svg i gdzie widać że jest niewypełniony ale jak tylko go wczytam to zachowuje się jak zwykły kwadrat z klasy Rectangle. W jaki sposób mógłbym to zrobić by mi rysowało i wczytywało kwadraty pełne jak i puste w środku?

https://github.com/szewcz/prog

0

Ten copy-paste który zrobiłeś teraz jest idiotyczny. A jak będziesz chciał mieć różne kolory to co? Dla każdego zrobisz osobną klasę? Powodzenia.
Może jednak zaczniesz coś myśleć? Skoro kwadraty różnią się tylko pewnym parametrem, który dodatkowo zapisujesz potem w XMLu to może łaskawie dodasz ten parametr do klasy a potem będziesz go z tego xmla czytał?
Srsly, chciałbym zobaczyć jak ogarniasz sytuację że każda figura może mieć 100 różnych kolorów. Zrobisz 100*liczba figur różnych klas?

0

No śpieszyłem się... Kolory sobie daruję
Z tym parametrem to rzeczywiście dojeb**em ;/ ale w jaki sposób program ma wiedzieć kiedy podczas rysowania na panelu miałby wykonać g.draw(rect) albo g.fill(rect)?

0

rób zawsze g.fill i odrysowuj brzeg, a jak ma być tylko kontur to nadaj 100% alfy do koloru :)

voila :D

albo stwórz hashmapę z róznymi odrysowaniami i paramtr w xml-u który będzie wyznaczał które odrysowanie złapać

0

Nie bardzo wiem w jaki sposób ta alfa ma mi pomóc w rozróżnianiu kiedy w programie podczas rysowania ma mi się pojawić kwadrat a kiedy kontur.
No i dalej nie wiem jak miałbym rysować kwadrat, kontur i je zapisywać, wczytywać oraz wyświetlać.

Już drugi dzień nad tym siedzę i już nie wytrzymuję. ;/

Proszę o pomoc bo chciałbym to mieć szybko z głowy.

0

jak dasz alfe na 100% to będziesz miał przezroczysty, czyli zostanie Ci sam kontur.......

0

Już rozwiązałem problem dzięki

1 użytkowników online, w tym zalogowanych: 0, gości: 1