¿Hay alguna forma de guardar formas y diseños en javafx en un archivo externo? Que luego se puede restaurar en un momento posterior. He intentado seguir videos de YouTube y sé cómo puedo guardar / cargar archivos con campos "Text / Int". Sin embargo, necesito una forma de cargar el último diseño guardado.

Por ejemplo, digamos que quiero guardar un polígono, he creado la siguiente clase:

import javafx.scene.shape.Polygon;

public class saveFile implements java.io.Serializable {
    private static final long serialVersionUID = 1L;
    public Polygon fp; 
    }

Clase de administrador de recursos:

import java.io.ObjectInputStream; 
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.nio.file.Files;
import java.nio.file.Paths;

public class ResourceManager {

public static void save(Serializable data, String fileName) throws Exception  {
    try (ObjectOutputStream oos = new ObjectOutputStream(Files.newOutputStream(Paths.get(fileName)))) {
        oos.writeObject(data);
    }
}

public static Object load(String fileName) throws Exception {
    try (ObjectInputStream ois = new ObjectInputStream(Files.newInputStream(Paths.get(fileName)))) {
        return ois.readObject();
    }
}
}

Clase de controlador:

//Field
private Polygon fp = new Polygon();
@FXML
private AnchorPane container2;

//Methods
public void saveLayout(){
    saveFile data = new saveFile();
    data.fp = fp;
    try {
        ResourceManager.save(data, "savefile");
    } catch (Exception e) {
        System.out.println("Error");
    }
}

public void loadLayout() throws IOException {
    try {
        saveFile data = (saveFile) ResourceManager.load("save");
        container2.getChildren().add(data.fp);
    }
    catch(Exception e){
        System.out.println("Error");
    }
}

Sé que el método de carga es completamente incorrecto en este momento, sin embargo, pensé que sería bueno proporcionarlo de todos modos.

Editar: e.printStackTrace (); devuelto:

java.io.NotSerializableException: javafx.scene.shape.Polygon
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)
at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
at Model.ResourceManager.save(ResourceManager.java:14)
at Controller.NewLayoutController.saveLayout(NewLayoutController.java:191)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at sun.reflect.misc.Trampoline.invoke(MethodUtil.java:71)
at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at sun.reflect.misc.MethodUtil.invoke(MethodUtil.java:275)
at javafx.fxml.FXMLLoader$MethodHandler.invoke(FXMLLoader.java:1771)
at javafx.fxml.FXMLLoader$ControllerMethodEventHandler.handle(FXMLLoader.java:1657)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:49)
at javafx.event.Event.fireEvent(Event.java:198)
at javafx.scene.control.MenuItem.fire(MenuItem.java:462)
at com.sun.javafx.scene.control.skin.ContextMenuContent$MenuItemContainer.doSelect(ContextMenuContent.java:1405)
at com.sun.javafx.scene.control.skin.ContextMenuContent$MenuItemContainer.lambda$createChildren$343(ContextMenuContent.java:1358)
at com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:218)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
at javafx.event.Event.fireEvent(Event.java:198)
at javafx.scene.Scene$MouseHandler.process(Scene.java:3757)
at javafx.scene.Scene$MouseHandler.access$1500(Scene.java:3485)
at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1762)
at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2494)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:352)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:275)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$355(GlassViewEventHandler.java:388)
at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:389)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:387)
at com.sun.glass.ui.View.handleMouseEvent(View.java:555)
at com.sun.glass.ui.View.notifyMouse(View.java:937)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$149(WinApplication.java:191)
at java.lang.Thread.run(Thread.java:745)
1
TheBeliever12 16 ene. 2017 a las 17:23
Y cual es el problema exacto? Su código debería funcionar como está ahora.
 – 
Enigo
16 ene. 2017 a las 20:36
El problema es que cuando hago clic en el botón "Guardar" en el programa, devuelve la excepción "Error". No lo guarda en un archivo externo.
 – 
TheBeliever12
16 ene. 2017 a las 22:02
¿Y cuál es la excepción?
 – 
Enigo
16 ene. 2017 a las 22:51
La excepción imprime el mensaje "Error" que he declarado en la excepción. No entiendo por qué no lo salva. Me ha estado confundiendo todo el día
 – 
TheBeliever12
16 ene. 2017 a las 23:18
Bueno, deberías imprimir e, también para desentrañar ese misterio)) System.out.println("Error", e); pero es mejor que uses logback o algo
 – 
Enigo
16 ene. 2017 a las 23:52

1 respuesta

La mejor respuesta

El problema es que la clase Polygon no implementa la interfaz Serializable, por eso no se puede serializar con los medios estándar de Java. Para la clase Polygon bastaría con guardar solo sus puntos para recuperarlos más tarde:

public static void save(ObservableList<Double> points, String fileName) throws Exception  {
    try (ObjectOutputStream oos = new ObjectOutputStream(Files.newOutputStream(Paths.get(fileName)))) {
          oos.writeObject(new ArrayList<>(points));
    }
}

Y luego volver a leerlo:

public static ObservableList<Double> load(String fileName) throws Exception {
    try (ObjectInputStream ois = new ObjectInputStream(Files.newInputStream(Paths.get(fileName)))) {
        List<Double> list = (List<Double>) ois.readObject();
        return FXCollections.observableList(list);
    }
}

Y luego puedes construir un nuevo polígono como:

ObservableList<Double> points = ResourceManager.load("save");
Polygon polygon = new Polygon()
polygon.getPoints().addAll(points);
3
Enigo 23 mar. 2020 a las 22:23
Y una vez más, para una serialización más compleja, debería echar un vistazo a herramientas más complejas (como gson). Para Polygon es bastante simple, pero este enfoque puede ser suficiente para otras formas que necesita serializar.
 – 
Enigo
17 ene. 2017 a las 11:02
Bueno escuchar eso)
 – 
Enigo
17 ene. 2017 a las 22:42