在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文件时,需要重建模型,然后根据模型的状态创建视图。相关问题:。