Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/334.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在JavaFx上保存/加载窗格图形_Java_Intellij Idea_Javafx_Save_Pane - Fatal编程技术网

在JavaFx上保存/加载窗格图形

在JavaFx上保存/加载窗格图形,java,intellij-idea,javafx,save,pane,Java,Intellij Idea,Javafx,Save,Pane,我创建了一个绘画应用程序,在其中绘制形状并将其作为节点添加到窗格中。类似于下面的代码: currentShape = new Rectangle(); shapeList.add(currentShape); pane.getChildren().addAll(shapelist); 我想保存图形并能够加载已保存的图形。我不知道如何处理这个问题。我查看了使用以下类型的快照/可写映像的示例。但是,这给了我一个无法解决SwingFXUtils错误 save.setOnAction(event -&

我创建了一个绘画应用程序,在其中绘制形状并将其作为节点添加到窗格中。类似于下面的代码:

currentShape = new Rectangle();
shapeList.add(currentShape);
pane.getChildren().addAll(shapelist);
我想保存图形并能够加载已保存的图形。我不知道如何处理这个问题。我查看了使用以下类型的快照/可写映像的示例。但是,这给了我一个
无法解决SwingFXUtils
错误

save.setOnAction(event -> {
            FileChooser fileChooser = new FileChooser();

            //Set extension filter
            fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("png files (*.png)", "*.png"));

            //Prompt user to select a file
            File f = fileChooser.showSaveDialog(null);

            if(f != null){
                try {
                    //Pad the capture area
                    WritableImage writableImage = new WritableImage((int) pane.getWidth(), (int) pane.getHeight());
                    pane.snapshot(null, writableImage);
                    RenderedImage renderedImage = SwingFXUtils.fromFXImage(writableImage, null);
                    //Write the snapshot to the chosen file
                    ImageIO.write(renderedImage, "png", f);
                } catch (IOException ex)
                { ex.printStackTrace(); }

            }
        });

如果有人对如何在窗格中保存和加载图形有更好的建议,我将不胜感激。

Slaw是正确的:到目前为止,最好的方法是创建自己的模型对象,以表示应用程序中显示的内容

但是,如果您想尝试直接编写和读取JavaFX形状,您确实有一个选项:XMLBean序列化

XML bean序列化由和类执行

与常规Java序列化不同,它们不查看字段,只查看bean属性。bean属性由公共读取方法定义,该方法是以
get
开头的零参数方法(或者,如果它返回原语
boolean
,则可以选择以
is
而不是
get
开头)

因此,
getWidth()
方法的存在定义了一个名为
width
的属性

如果有一个对应的
set
方法(在上述情况下,它将是
setWidth
),它只接受get方法返回的同一类型的一个参数,则该属性被定义为可写属性

(完整的规则比这复杂一点;我只描述了一般情况。完整的JavaBeans规范是。)

如果您看过for JavaFX,您可能已经注意到JavaFX类定义了很多属性。这意味着您可以使用以下内容保存
窗格
子项:

private static final java.nio.file.Path SAVE_FILE_LOCATION =
    Paths.get(System.getProperty("user.home"), "shapes.xml");

void save()
throws IOException {
    try (XMLEncoder encoder = new XMLEncoder(
        new BufferedOutputStream(
            Files.newOutputStream(SAVE_FILE_LOCATION)))) {

        encoder.setExceptionListener(e -> {
            throw new RuntimeException(e);
        });

        encoder.writeObject(pane.getChildren().toArray(new Node[0]));
    }
}

void load()
throws IOException {
    try (XMLDecoder decoder = new XMLDecoder(
        new BufferedInputStream(
            Files.newInputStream(SAVE_FILE_LOCATION)))) {

        decoder.setExceptionListener(e -> {
            throw new RuntimeException(e);
        });

        pane.getChildren().setAll((Node[]) decoder.readObject());
    }
}
private static void addPersistenceDelegatesTo(Encoder encoder) {
    encoder.setPersistenceDelegate(Font.class,
        new DefaultPersistenceDelegate(
            new String[] { "name", "size" }));
    encoder.setPersistenceDelegate(Color.class,
        new DefaultPersistenceDelegate(
            new String[] { "red", "green", "blue", "opacity" }));
    encoder.setPersistenceDelegate(LinearGradient.class,
        new DefaultPersistenceDelegate(new String[] {
            "startX", "startY", "endX", "endY",
            "proportional", "cycleMethod", "stops"
        }));
    encoder.setPersistenceDelegate(RadialGradient.class,
        new DefaultPersistenceDelegate(new String[] {
            "focusAngle", "focusDistance", "centerX", "centerY",
            "radius", "proportional", "cycleMethod", "stops"
        }));
}

private static final java.nio.file.Path SAVE_FILE_LOCATION =
    Paths.get(System.getProperty("user.home"), "shapes.xml");

void save()
throws IOException {
    try (XMLEncoder encoder = new XMLEncoder(
        new BufferedOutputStream(
            Files.newOutputStream(SAVE_FILE_LOCATION)))) {

        encoder.setExceptionListener(e -> {
            throw new RuntimeException(e);
        });

        addPersistenceDelegatesTo(encoder);

        encoder.writeObject(pane.getChildren().toArray(new Node[0]));
    }
}

void load()
throws IOException {
    try (XMLDecoder decoder = new XMLDecoder(
        new BufferedInputStream(
            Files.newInputStream(SAVE_FILE_LOCATION)))) {

        decoder.setExceptionListener(e -> {
            throw new RuntimeException(e);
        });

        pane.getChildren().setAll((Node[]) decoder.readObject());
    }
}
然而,XMLEncoder对类的了解和直觉是有限的。例如,在上面的代码中,我使用的是
节点数组而不是原始的ObservableList,因为XMLEncoder不知道如何序列化ObservableList的任何具体实现(未公开文档)。但是,XMLEncoder具有序列化数组的内置功能,只要它能够序列化数组元素本身

更重要的问题是,它不知道如何序列化某些属性,只会忽略它们。例如,Color不是一个典型的javabean:它是只读的,因此尽管xmlcoder可以读取它的数据,但没有设置的方法,因此编码器不知道未来的xmldecord可以使用哪些指令来创建等效的Color对象

我们可以通过以下方式自定义XMLEncoder。方便的是,该子类允许将bean属性名传递给构造函数,构造函数将创建一个委托,该委托将告诉XMLDecoder查找一个构造函数,该构造函数采用与原始写入数据中的每个属性对应的参数

由于颜色具有接受、和属性值的属性,因此我们可以将DefaultPersistenceDelegate添加到XMLEncoder,它指示未来的XmlDecoder在重建颜色对象时使用这些属性的值:

encoder.setPersistenceDelegate(Color.class,
    new DefaultPersistenceDelegate(
        new String[] { "red", "green", "blue", "opacity" }));
上面的意思是:“在编写一个颜色对象时,为未来的解码器编写指令,以便在颜色类中查找一个接受四个双精度的构造函数,然后分别调用颜色对象的getRed、getGreen、getBlue和getOpacity方法,编写将来要传递的实际值。”

如果希望形状包含对象,可以为类添加持久性委托:

您还可以为其他Paint实现添加持久化代理:

encoder.setPersistenceDelegate(LinearGradient.class,
    new DefaultPersistenceDelegate(new String[] {
        "startX", "startY", "endX", "endY",
        "proportional", "cycleMethod", "stops"
    }));
encoder.setPersistenceDelegate(RadialGradient.class,
    new DefaultPersistenceDelegate(new String[] {
        "focusAngle", "focusDistance", "centerX", "centerY",
        "radius", "proportional", "cycleMethod", "stops"
    }));
(我故意省略了ImagePattern,因为虽然可以用XML表示图像,但它既丑陋又低效。如果要存储图像,XML不是一种好的存储格式。)

因此,加载和存储方法的更新版本如下所示:

private static final java.nio.file.Path SAVE_FILE_LOCATION =
    Paths.get(System.getProperty("user.home"), "shapes.xml");

void save()
throws IOException {
    try (XMLEncoder encoder = new XMLEncoder(
        new BufferedOutputStream(
            Files.newOutputStream(SAVE_FILE_LOCATION)))) {

        encoder.setExceptionListener(e -> {
            throw new RuntimeException(e);
        });

        encoder.writeObject(pane.getChildren().toArray(new Node[0]));
    }
}

void load()
throws IOException {
    try (XMLDecoder decoder = new XMLDecoder(
        new BufferedInputStream(
            Files.newInputStream(SAVE_FILE_LOCATION)))) {

        decoder.setExceptionListener(e -> {
            throw new RuntimeException(e);
        });

        pane.getChildren().setAll((Node[]) decoder.readObject());
    }
}
private static void addPersistenceDelegatesTo(Encoder encoder) {
    encoder.setPersistenceDelegate(Font.class,
        new DefaultPersistenceDelegate(
            new String[] { "name", "size" }));
    encoder.setPersistenceDelegate(Color.class,
        new DefaultPersistenceDelegate(
            new String[] { "red", "green", "blue", "opacity" }));
    encoder.setPersistenceDelegate(LinearGradient.class,
        new DefaultPersistenceDelegate(new String[] {
            "startX", "startY", "endX", "endY",
            "proportional", "cycleMethod", "stops"
        }));
    encoder.setPersistenceDelegate(RadialGradient.class,
        new DefaultPersistenceDelegate(new String[] {
            "focusAngle", "focusDistance", "centerX", "centerY",
            "radius", "proportional", "cycleMethod", "stops"
        }));
}

private static final java.nio.file.Path SAVE_FILE_LOCATION =
    Paths.get(System.getProperty("user.home"), "shapes.xml");

void save()
throws IOException {
    try (XMLEncoder encoder = new XMLEncoder(
        new BufferedOutputStream(
            Files.newOutputStream(SAVE_FILE_LOCATION)))) {

        encoder.setExceptionListener(e -> {
            throw new RuntimeException(e);
        });

        addPersistenceDelegatesTo(encoder);

        encoder.writeObject(pane.getChildren().toArray(new Node[0]));
    }
}

void load()
throws IOException {
    try (XMLDecoder decoder = new XMLDecoder(
        new BufferedInputStream(
            Files.newInputStream(SAVE_FILE_LOCATION)))) {

        decoder.setExceptionListener(e -> {
            throw new RuntimeException(e);
        });

        pane.getChildren().setAll((Node[]) decoder.readObject());
    }
}

您需要导入SwingFXUtils,就像您想要调用其方法的任何其他类一样。至于保存,如果只保存快照,将丢失有关各个形状的所有信息;您可以接受吗?导入SwingFXUtils,如导入javafx.embed.swing.SwingFXUtils给我以下错误
无法解析符号嵌入
。不,我想保留这些信息,因为我需要加载相同的形状如果您使用的是JavaFX 9+,请注意
SwingFXUtils
位于
JavaFX.swing
模块中,必须在模块路径上解析,如果您的代码是模块化的,则模块需要它。但快照并不是正确的方法。您应该设计一个模型来表示屏幕上显示的内容。这是你保存的模型。具体怎么做取决于你自己。例如,您可以将模型状态保存到XML或JSON文件中。加载XML/JSON文件时,需要重建模型,然后根据模型的状态创建视图。相关问题:。