增加组件的旋转

This commit is contained in:
liujing133
2025-12-06 00:27:43 +08:00
parent 6b31c8051d
commit fb7e360152
6 changed files with 115 additions and 18 deletions
@@ -12,6 +12,7 @@ public abstract class DrawableObject implements Serializable {
protected double height; protected double height;
protected String id; protected String id;
protected boolean selected; protected boolean selected;
protected double rotation = 0;
public DrawableObject(double x, double y, double width, double height) { public DrawableObject(double x, double y, double width, double height) {
this.x = x; this.x = x;
@@ -70,6 +71,14 @@ public abstract class DrawableObject implements Serializable {
this.selected = selected; this.selected = selected;
} }
public double getRotation() {
return rotation;
}
public void setRotation(double rotation) {
this.rotation = (rotation % 360 + 360) % 360;
}
/** /**
* 检查点是否在对象内 * 检查点是否在对象内
*/ */
@@ -274,6 +274,19 @@ public class DrawingCanvas extends Pane {
* 绘制单个对象 * 绘制单个对象
*/ */
private void drawObject(GraphicsContext gc, DrawableObject obj, boolean selected) { private void drawObject(GraphicsContext gc, DrawableObject obj, boolean selected) {
// 保存当前状态
gc.save();
// 计算旋转中心(对象中心)
double centerX = obj.getX() + obj.getWidth() / 2;
double centerY = obj.getY() + obj.getHeight() / 2;
// 应用旋转
gc.translate(centerX, centerY);
gc.rotate(obj.getRotation());
gc.translate(-centerX, -centerY);
// 绘制具体对象
if (obj instanceof TextObject) { if (obj instanceof TextObject) {
drawTextObject(gc, (TextObject) obj, selected); drawTextObject(gc, (TextObject) obj, selected);
} else if (obj instanceof ShapeObject) { } else if (obj instanceof ShapeObject) {
@@ -281,7 +294,10 @@ public class DrawingCanvas extends Pane {
} else if (obj instanceof ImageObject) { } else if (obj instanceof ImageObject) {
drawImageObject(gc, (ImageObject) obj, selected); drawImageObject(gc, (ImageObject) obj, selected);
} }
}
// 恢复状态
gc.restore();
}
/** /**
* 绘制文本对象 * 绘制文本对象
@@ -1,10 +1,16 @@
package dev.bytevibe.hyperpoint; package dev.bytevibe.hyperpoint;
import com.google.gson.*; import java.io.File;
import javafx.scene.paint.Color; import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.*; import com.google.gson.Gson;
import java.util.*; import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
/** /**
* JSON序列化工具,用于将演示文稿保存和加载为JSON格式 * JSON序列化工具,用于将演示文稿保存和加载为JSON格式
@@ -180,6 +186,7 @@ public class JsonSerializationUtil {
ImageObject imgObj = (ImageObject) obj; ImageObject imgObj = (ImageObject) obj;
objJson.addProperty("imagePath", imgObj.getImagePath()); objJson.addProperty("imagePath", imgObj.getImagePath());
} }
objJson.addProperty("rotation", obj.getRotation()); // 添加旋转角度
return objJson; return objJson;
} }
@@ -238,6 +245,11 @@ public class JsonSerializationUtil {
obj = new ImageObject(x, y, width, height, imagePath); obj = new ImageObject(x, y, width, height, imagePath);
} }
// 读取旋转角度并设置
if (objJson.has("rotation")) {
obj.setRotation(objJson.get("rotation").getAsDouble());
}
if (obj != null) { if (obj != null) {
obj.setId(id); obj.setId(id);
} }
@@ -584,6 +584,15 @@ public class PresentationWindow {
* 绘制单个对象 * 绘制单个对象
*/ */
private void drawObject(GraphicsContext gc, DrawableObject obj) { private void drawObject(GraphicsContext gc, DrawableObject obj) {
gc.save();
double centerX = obj.getX() + obj.getWidth() / 2;
double centerY = obj.getY() + obj.getHeight() / 2;
gc.translate(centerX, centerY);
gc.rotate(obj.getRotation());
gc.translate(-centerX, -centerY);
if (obj instanceof TextObject) { if (obj instanceof TextObject) {
drawTextObject(gc, (TextObject) obj); drawTextObject(gc, (TextObject) obj);
} else if (obj instanceof ShapeObject) { } else if (obj instanceof ShapeObject) {
@@ -591,6 +600,8 @@ public class PresentationWindow {
} else if (obj instanceof ImageObject) { } else if (obj instanceof ImageObject) {
drawImageObject(gc, (ImageObject) obj); drawImageObject(gc, (ImageObject) obj);
} }
gc.restore();
} }
/** /**
@@ -1,16 +1,22 @@
package dev.bytevibe.hyperpoint; package dev.bytevibe.hyperpoint;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.control.*;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import java.io.IOException; import java.io.IOException;
import java.net.URL; import java.net.URL;
import java.util.ResourceBundle; import java.util.ResourceBundle;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.ColorPicker;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.control.Slider;
import javafx.scene.control.Spinner;
import javafx.scene.control.TextField;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
/** /**
* 属性编辑面板,用于编辑选中对象的属性 * 属性编辑面板,用于编辑选中对象的属性
* 使用FXML加载UI布局 * 使用FXML加载UI布局
@@ -38,6 +44,10 @@ public class PropertyPanel extends VBox implements Initializable {
private Spinner<Double> strokeWidthSpinner; private Spinner<Double> strokeWidthSpinner;
@FXML @FXML
private Button deleteButton; private Button deleteButton;
@FXML
private Slider rotationSlider;
@FXML
private Label rotationValueLabel;
private DrawingCanvas canvas; private DrawingCanvas canvas;
@@ -80,6 +90,20 @@ public class PropertyPanel extends VBox implements Initializable {
"BOLD_ITALIC" "BOLD_ITALIC"
); );
// 初始化旋转控制
rotationSlider.setMin(0);
rotationSlider.setMax(360);
rotationSlider.setValue(0);
rotationSlider.setMajorTickUnit(15);
rotationSlider.setMajorTickUnit(90);
rotationSlider.setShowTickMarks(true);
rotationSlider.setShowTickLabels(true);
rotationSlider.valueProperty().addListener((obs, oldVal, newVal) -> {
updateRotation();
rotationValueLabel.setText(String.format("%.0f°", newVal));
});
// 设置默认值 // 设置默认值
fontFamilyCombo.setValue("Arial"); fontFamilyCombo.setValue("Arial");
fontStyleCombo.setValue("NORMAL"); fontStyleCombo.setValue("NORMAL");
@@ -112,6 +136,7 @@ public class PropertyPanel extends VBox implements Initializable {
DrawableObject selected = canvas.getSelectedObject(); DrawableObject selected = canvas.getSelectedObject();
if (selected == null) { if (selected == null) {
setEditingVisible(false); setEditingVisible(false);
rotationSlider.setDisable(true);
objectTypeLabel.setText("未选中对象"); objectTypeLabel.setText("未选中对象");
return; return;
} }
@@ -142,15 +167,31 @@ public class PropertyPanel extends VBox implements Initializable {
showImageControls(); showImageControls();
} }
rotationSlider.setValue(selected.getRotation());
rotationSlider.setDisable(false);
rotationValueLabel.setText(String.format("%.0f°", selected.getRotation()));
// 重新添加监听 // 重新添加监听
textContentField.setOnKeyReleased(e -> updateTextContent()); textContentField.setOnKeyReleased(e -> updateTextContent());
} }
/**
* 更新旋转
*/
private void updateRotation() {
DrawableObject selected = canvas.getSelectedObject();
if (selected != null) {
selected.setRotation(rotationSlider.getValue());
canvas.redraw();
}
}
/** /**
* 显示文本控件 * 显示文本控件
*/ */
private void showTextControls() { private void showTextControls() {
textContentField.setDisable(false); textContentField.setDisable(false);
rotationSlider.setDisable(false);
fontFamilyCombo.setDisable(false); fontFamilyCombo.setDisable(false);
fontSizeSpinner.setDisable(false); fontSizeSpinner.setDisable(false);
fontStyleCombo.setDisable(false); fontStyleCombo.setDisable(false);
@@ -167,6 +208,7 @@ public class PropertyPanel extends VBox implements Initializable {
*/ */
private void showShapeControls() { private void showShapeControls() {
textContentField.setDisable(true); textContentField.setDisable(true);
rotationSlider.setDisable(false);
fontFamilyCombo.setDisable(true); fontFamilyCombo.setDisable(true);
fontSizeSpinner.setDisable(true); fontSizeSpinner.setDisable(true);
fontStyleCombo.setDisable(true); fontStyleCombo.setDisable(true);
@@ -183,6 +225,7 @@ public class PropertyPanel extends VBox implements Initializable {
*/ */
private void showImageControls() { private void showImageControls() {
textContentField.setDisable(true); textContentField.setDisable(true);
rotationSlider.setDisable(false);
fontFamilyCombo.setDisable(true); fontFamilyCombo.setDisable(true);
fontSizeSpinner.setDisable(true); fontSizeSpinner.setDisable(true);
fontStyleCombo.setDisable(true); fontStyleCombo.setDisable(true);
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Slider?>
<?import javafx.scene.control.Button?> <?import javafx.scene.control.Button?>
<?import javafx.scene.control.ColorPicker?> <?import javafx.scene.control.ColorPicker?>
<?import javafx.scene.control.ComboBox?> <?import javafx.scene.control.ComboBox?>
@@ -23,6 +24,11 @@
<Separator/> <Separator/>
<!-- 旋转角度 -->
<Slider fx:id="rotationSlider" max="360.0" min="0.0" />
<Label text="旋转角度:" />
<Label fx:id="rotationValueLabel" text="0°" />
<!-- 文本内容 --> <!-- 文本内容 -->
<Label text="文本内容:"/> <Label text="文本内容:"/>
<TextField fx:id="textContentField"/> <TextField fx:id="textContentField"/>