增加组件的旋转
This commit is contained in:
@@ -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,15 +274,31 @@ public class DrawingCanvas extends Pane {
|
|||||||
* 绘制单个对象
|
* 绘制单个对象
|
||||||
*/
|
*/
|
||||||
private void drawObject(GraphicsContext gc, DrawableObject obj, boolean selected) {
|
private void drawObject(GraphicsContext gc, DrawableObject obj, boolean selected) {
|
||||||
if (obj instanceof TextObject) {
|
// 保存当前状态
|
||||||
drawTextObject(gc, (TextObject) obj, selected);
|
gc.save();
|
||||||
} else if (obj instanceof ShapeObject) {
|
|
||||||
drawShapeObject(gc, (ShapeObject) obj, selected);
|
// 计算旋转中心(对象中心)
|
||||||
} else if (obj instanceof ImageObject) {
|
double centerX = obj.getX() + obj.getWidth() / 2;
|
||||||
drawImageObject(gc, (ImageObject) obj, selected);
|
double centerY = obj.getY() + obj.getHeight() / 2;
|
||||||
}
|
|
||||||
|
// 应用旋转
|
||||||
|
gc.translate(centerX, centerY);
|
||||||
|
gc.rotate(obj.getRotation());
|
||||||
|
gc.translate(-centerX, -centerY);
|
||||||
|
|
||||||
|
// 绘制具体对象
|
||||||
|
if (obj instanceof TextObject) {
|
||||||
|
drawTextObject(gc, (TextObject) obj, selected);
|
||||||
|
} else if (obj instanceof ShapeObject) {
|
||||||
|
drawShapeObject(gc, (ShapeObject) obj, selected);
|
||||||
|
} else if (obj instanceof ImageObject) {
|
||||||
|
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"/>
|
||||||
|
|||||||
Reference in New Issue
Block a user