feature:实现了文件的保存和读取

This commit is contained in:
2025-11-24 16:25:25 +08:00
parent 43e1f76f8c
commit f7e77cdc5d
6 changed files with 346 additions and 3 deletions
+7
View File
@@ -27,6 +27,13 @@
<version>${javafx.version}</version>
</dependency>
<!-- Gson库,用于JSON序列化 -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10.1</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
@@ -46,6 +46,10 @@ public class Controller implements Initializable {
private VBox propertyPanelContainer;
@FXML
private AnchorPane scenePane;
@FXML
private Button openSlideButton; // 添加打开幻灯片按钮
@FXML
private Button saveSlideButton; // 添加保存幻灯片按钮
private Slide currentSlide;
private DrawingCanvas drawingCanvas;
@@ -346,6 +350,86 @@ public class Controller implements Initializable {
}
}
/**
* 打开幻灯片文件
*/
@FXML
public void onOpenSlideFile(ActionEvent actionEvent) {
FileChooser fileChooser = new FileChooser();
fileChooser.setTitle("打开幻灯片");
fileChooser.getExtensionFilters().addAll(
new FileChooser.ExtensionFilter("幻灯片文件 (*.hyperpoint)", "*.hyperpoint"),
new FileChooser.ExtensionFilter("所有文件", "*.*")
);
stage = (Stage) openSlideButton.getScene().getWindow();
File file = fileChooser.showOpenDialog(stage);
if (file != null) {
try {
Presentation presentation = JsonSerializationUtil.loadFromJson(file);
currentSlide = presentation.getSlides().isEmpty() ? null : presentation.getSlides().get(0);
if (currentSlide != null) {
loadSlidePages();
stage.setTitle("Hyperpoint - " + presentation.getName());
MyAlert alert = new MyAlert(Alert.AlertType.INFORMATION);
alert.setTitle("成功");
alert.setHeaderText("幻灯片已打开");
alert.setContentText("幻灯片 \"" + presentation.getName() + "\" 已成功加载,包含 " + currentSlide.getPages().size() + " 个页面。");
alert.showAndWait();
} else {
showWarning("加载失败", "幻灯片中没有找到任何页面。");
}
} catch (Exception e) {
showWarning("错误", "无法加载幻灯片文件: " + e.getMessage());
e.printStackTrace();
}
}
}
/**
* 保存幻灯片文件
*/
@FXML
public void onSaveSlide(ActionEvent actionEvent) {
if (currentSlide == null) {
showWarning("无幻灯片", "请先创建或打开一个幻灯片。");
return;
}
FileChooser fileChooser = new FileChooser();
fileChooser.setTitle("保存幻灯片");
fileChooser.getExtensionFilters().addAll(
new FileChooser.ExtensionFilter("幻灯片文件", "*.hyperpoint"),
new FileChooser.ExtensionFilter("所有文件", "*.*")
);
fileChooser.setInitialFileName(currentSlide.getName() + ".hyperpoint");
stage = (Stage) saveSlideButton.getScene().getWindow();
File file = fileChooser.showSaveDialog(stage);
if (file != null) {
try {
// 创建临时演示文稿对象用于保存
Presentation tempPresentation = new Presentation(currentSlide.getName());
tempPresentation.addSlide(currentSlide);
JsonSerializationUtil.saveToJson(tempPresentation, file);
MyAlert alert = new MyAlert(Alert.AlertType.INFORMATION);
alert.setTitle("成功");
alert.setHeaderText("幻灯片已保存");
alert.setContentText("幻灯片已保存到: " + file.getAbsolutePath());
alert.showAndWait();
} catch (Exception e) {
showWarning("错误", "无法保存幻灯片文件: " + e.getMessage());
e.printStackTrace();
}
}
}
/**
* 显示警告对话框
*/
@@ -357,4 +441,3 @@ public class Controller implements Initializable {
alert.showAndWait();
}
}
@@ -58,6 +58,10 @@ public abstract class DrawableObject implements Serializable {
return id;
}
public void setId(String id) {
this.id = id;
}
public boolean isSelected() {
return selected;
}
@@ -0,0 +1,248 @@
package dev.bytevibe.hyperpoint;
import com.google.gson.*;
import javafx.scene.paint.Color;
import java.io.*;
import java.util.*;
/**
* JSON序列化工具,用于将演示文稿保存和加载为JSON格式
*/
public class JsonSerializationUtil {
private static final Gson gson = new GsonBuilder()
.setPrettyPrinting()
.create();
/**
* 将演示文稿保存为JSON文件
*/
public static void saveToJson(Presentation presentation, File file) throws IOException {
JsonObject root = new JsonObject();
// 保存演示文稿基本信息
root.addProperty("name", presentation.getName());
// 保存所有幻灯片
JsonArray slidesArray = new JsonArray();
for (Slide slide : presentation.getSlides()) {
slidesArray.add(serializeSlide(slide));
}
root.add("slides", slidesArray);
// 写入文件
try (FileWriter writer = new FileWriter(file)) {
gson.toJson(root, writer);
}
}
/**
* 从JSON文件加载演示文稿
*/
public static Presentation loadFromJson(File file) throws IOException {
// 读取文件
String jsonContent;
try (FileReader reader = new FileReader(file)) {
jsonContent = new String(new byte[]{});
StringBuilder sb = new StringBuilder();
int c;
while ((c = reader.read()) != -1) {
sb.append((char) c);
}
jsonContent = sb.toString();
}
// 解析JSON
JsonObject root = JsonParser.parseString(jsonContent).getAsJsonObject();
String name = root.get("name").getAsString();
Presentation presentation = new Presentation(name);
// 加载所有幻灯片
JsonArray slidesArray = root.getAsJsonArray("slides");
for (JsonElement slideElement : slidesArray) {
presentation.addSlide(deserializeSlide(slideElement.getAsJsonObject()));
}
return presentation;
}
/**
* 序列化幻灯片
*/
private static JsonObject serializeSlide(Slide slide) {
JsonObject slideObj = new JsonObject();
slideObj.addProperty("id", slide.getId());
slideObj.addProperty("name", slide.getName());
// 序列化所有页面
JsonArray pagesArray = new JsonArray();
for (SlidePage page : slide.getPages()) {
pagesArray.add(serializePage(page));
}
slideObj.add("pages", pagesArray);
return slideObj;
}
/**
* 反序列化幻灯片
*/
private static Slide deserializeSlide(JsonObject slideObj) {
String name = slideObj.get("name").getAsString();
Slide slide = new Slide(name);
// 清除默认页面
slide.getPages().clear();
// 加载所有页面
JsonArray pagesArray = slideObj.getAsJsonArray("pages");
for (JsonElement pageElement : pagesArray) {
slide.getPages().add(deserializePage(pageElement.getAsJsonObject()));
}
return slide;
}
/**
* 序列化页面
*/
private static JsonObject serializePage(SlidePage page) {
JsonObject pageObj = new JsonObject();
pageObj.addProperty("id", page.getId());
pageObj.addProperty("title", page.getTitle());
pageObj.addProperty("content", page.getContent());
// 序列化页面中的所有可绘制对象
JsonArray objectsArray = new JsonArray();
for (DrawableObject obj : page.getPageContent().getDrawableObjects()) {
objectsArray.add(serializeDrawableObject(obj));
}
pageObj.add("objects", objectsArray);
return pageObj;
}
/**
* 反序列化页面
*/
private static SlidePage deserializePage(JsonObject pageObj) {
String id = pageObj.get("id").getAsString();
String title = pageObj.get("title").getAsString();
String content = pageObj.has("content") ? pageObj.get("content").getAsString() : "";
SlidePage page = new SlidePage(title);
page.setId(id);
page.setContent(content);
// 加载所有可绘制对象
if (pageObj.has("objects")) {
JsonArray objectsArray = pageObj.getAsJsonArray("objects");
for (JsonElement objElement : objectsArray) {
DrawableObject obj = deserializeDrawableObject(objElement.getAsJsonObject());
if (obj != null) {
page.getPageContent().addObject(obj);
}
}
}
return page;
}
/**
* 序列化可绘制对象
*/
private static JsonObject serializeDrawableObject(DrawableObject obj) {
JsonObject objJson = new JsonObject();
objJson.addProperty("id", obj.getId());
objJson.addProperty("x", obj.getX());
objJson.addProperty("y", obj.getY());
objJson.addProperty("width", obj.getWidth());
objJson.addProperty("height", obj.getHeight());
objJson.addProperty("type", obj.getTypeName());
if (obj instanceof TextObject) {
TextObject textObj = (TextObject) obj;
objJson.addProperty("text", textObj.getText());
objJson.addProperty("fontFamily", textObj.getFontFamily());
objJson.addProperty("fontSize", textObj.getFontSize());
objJson.addProperty("fontStyle", textObj.getFontStyle());
objJson.addProperty("textColor", textObj.getTextColor());
} else if (obj instanceof ShapeObject) {
ShapeObject shapeObj = (ShapeObject) obj;
objJson.addProperty("shapeType", shapeObj.getShapeType().name());
objJson.addProperty("fillColor", shapeObj.getFillColor());
objJson.addProperty("strokeColor", shapeObj.getStrokeColor());
objJson.addProperty("strokeWidth", shapeObj.getStrokeWidth());
} else if (obj instanceof ImageObject) {
ImageObject imgObj = (ImageObject) obj;
objJson.addProperty("imagePath", imgObj.getImagePath());
}
return objJson;
}
/**
* 反序列化可绘制对象
*/
private static DrawableObject deserializeDrawableObject(JsonObject objJson) {
String type = objJson.get("type").getAsString();
double x = objJson.get("x").getAsDouble();
double y = objJson.get("y").getAsDouble();
double width = objJson.get("width").getAsDouble();
double height = objJson.get("height").getAsDouble();
String id = objJson.get("id").getAsString();
DrawableObject obj = null;
if (type.equals("Text")) {
String text = objJson.get("text").getAsString();
obj = new TextObject(x, y, text);
obj.setWidth(width);
obj.setHeight(height);
TextObject textObj = (TextObject) obj;
if (objJson.has("fontFamily")) {
textObj.setFontFamily(objJson.get("fontFamily").getAsString());
}
if (objJson.has("fontSize")) {
textObj.setFontSize(objJson.get("fontSize").getAsDouble());
}
if (objJson.has("fontStyle")) {
textObj.setFontStyle(objJson.get("fontStyle").getAsString());
}
if (objJson.has("textColor")) {
textObj.setTextColor(objJson.get("textColor").getAsString());
}
} else if (type.startsWith("Shape_")) {
String shapeTypeStr = type.replace("Shape_", "");
ShapeObject.ShapeType shapeType = ShapeObject.ShapeType.valueOf(shapeTypeStr);
obj = new ShapeObject(x, y, width, height, shapeType);
ShapeObject shapeObj = (ShapeObject) obj;
if (objJson.has("fillColor")) {
shapeObj.setFillColor(objJson.get("fillColor").getAsString());
}
if (objJson.has("strokeColor")) {
shapeObj.setStrokeColor(objJson.get("strokeColor").getAsString());
}
if (objJson.has("strokeWidth")) {
shapeObj.setStrokeWidth(objJson.get("strokeWidth").getAsDouble());
}
} else if (type.equals("Image")) {
String imagePath = objJson.get("imagePath").getAsString();
obj = new ImageObject(x, y, width, height, imagePath);
}
if (obj != null) {
obj.setId(id);
}
return obj;
}
}
+1
View File
@@ -2,6 +2,7 @@ module dev.bytevibe.hyperpoint {
requires javafx.controls;
requires javafx.fxml;
requires java.desktop;
requires com.google.gson;
opens dev.bytevibe.hyperpoint to javafx.fxml;
@@ -15,10 +15,10 @@
<HBox spacing="5" style="-fx-padding: 5;">
<children>
<Button fx:id="newSlideButton" mnemonicParsing="false" onAction="#onNewSlide" text="新建幻灯片" />
<Button mnemonicParsing="false" text="打开幻灯片" />
<Button fx:id="openSlideButton" mnemonicParsing="false" onAction="#onOpenSlideFile" text="打开幻灯片" />
<Button fx:id="newPageButton" mnemonicParsing="false" onAction="#onNewPage" text="新建页面" />
<Button fx:id="deletePageButton" mnemonicParsing="false" onAction="#onDeletePage" text="删除页面" />
<Button mnemonicParsing="false" text="保存幻灯片" />
<Button fx:id="saveSlideButton" mnemonicParsing="false" onAction="#onSaveSlide" text="保存幻灯片" />
<Label text=" | " />
<Button fx:id="addTextButton" mnemonicParsing="false" onAction="#onAddText" text="添加文本" />
<Button fx:id="addLineButton" mnemonicParsing="false" onAction="#onAddLine" text="直线" />