优化撤销重做:组件的修改和删除

This commit is contained in:
liujing133
2025-12-06 21:55:13 +08:00
parent fb7e360152
commit 12437bb6a6
4 changed files with 303 additions and 47 deletions
@@ -136,6 +136,7 @@ public class Controller implements Initializable {
// 创建新的Canvas
PageContent pageContent = page.getPageContent();
drawingCanvas = new DrawingCanvas(pageContent);
drawingCanvas.setCurrentPage(page); // 设置当前页面
drawingCanvas.setCommandHistory(commandHistory); // 设置命令历史
drawingCanvasContainer.getChildren().add(drawingCanvas);
@@ -29,6 +29,8 @@ public class DrawingCanvas extends Pane {
private double lastX, lastY;
private Runnable onSelectionChanged;
private CommandHistory commandHistory;
private double startX, startY, startWidth, startHeight;
private SlidePage currentPage;
// 缩放点有关的属性
private ResizePoint resizePoint = ResizePoint.NONE;
@@ -67,8 +69,18 @@ public class DrawingCanvas extends Pane {
if (selectedObject != null) {
resizePoint = getResizePointAt(lastX, lastY, selectedObject);
if (resizePoint != ResizePoint.NONE) {
// 点击在调整点上,进入缩放模式
// 记录初始状态用于创建命令
startX = selectedObject.getX();
startY = selectedObject.getY();
startWidth = selectedObject.getWidth();
startHeight = selectedObject.getHeight();
return;
} else if (isPointInObject(lastX, lastY, selectedObject)) {
// 记录移动前的位置
startX = selectedObject.getX();
startY = selectedObject.getY();
startWidth = selectedObject.getWidth();
startHeight = selectedObject.getHeight();
}
}
@@ -87,6 +99,14 @@ public class DrawingCanvas extends Pane {
redraw();
}
/**
* 检查判断点是否在对象内
*/
private boolean isPointInObject(double x, double y, DrawableObject obj) {
return x >= obj.getX() && x <= obj.getX() + obj.getWidth() &&
y >= obj.getY() && y <= obj.getY() + obj.getHeight();
}
/**
* 获取点击位置对应的调整点
*/
@@ -195,9 +215,23 @@ public class DrawingCanvas extends Pane {
* 鼠标释放事件处理
*/
private void handleMouseReleased(MouseEvent event) {
// 如果有选中对象且位置或尺寸发生了变化,创建命令
if (selectedObject != null && commandHistory != null) {
if (selectedObject.getX() != startX || selectedObject.getY() != startY ||
selectedObject.getWidth() != startWidth || selectedObject.getHeight() != startHeight) {
Command command = new ModifyObjectCommand(
selectedObject,
startX, startY, startWidth, startHeight,
selectedObject.getX(), selectedObject.getY(),
selectedObject.getWidth(), selectedObject.getHeight()
);
commandHistory.execute(command);
}
}
// 释放鼠标时,重置缩放模式
resizePoint = ResizePoint.NONE;
}
}
/**
* 添加可绘制对象
@@ -249,6 +283,27 @@ public class DrawingCanvas extends Pane {
this.commandHistory = commandHistory;
}
/**
* 获取命令历史
*/
public CommandHistory getCommandHistory() {
return commandHistory;
}
/**
* 设置当前页面
*/
public void setCurrentPage(SlidePage page) {
this.currentPage = page;
}
/**
* 获取当前页面
*/
public SlidePage getCurrentPage() {
return currentPage;
}
/**
* 重新绘制画布
*/
@@ -0,0 +1,124 @@
package dev.bytevibe.hyperpoint;
/**
* 修改对象属性命令(除位置和尺寸外的其他属性)
*/
public class ModifyObjectPropertyCommand implements Command {
private DrawableObject object;
private String oldText;
private String newText;
private String oldFontFamily;
private String newFontFamily;
private double oldFontSize;
private double newFontSize;
private String oldFontStyle;
private String newFontStyle;
private String oldTextColor;
private String newTextColor;
private String oldFillColor;
private String newFillColor;
private String oldStrokeColor;
private String newStrokeColor;
private double oldStrokeWidth;
private double newStrokeWidth;
private double oldRotation;
private double newRotation;
private PropertyType propertyType;
// 定义属性类型枚举
public enum PropertyType {
TEXT, FONT, COLOR, ROTATION, SHAPE_STYLE
}
// 文本内容修改构造函数
public ModifyObjectPropertyCommand(TextObject object, String oldText, String newText, int nothing) {
this.object = object;
this.oldText = oldText;
this.newText = newText;
this.propertyType = PropertyType.TEXT;
}
// 字体样式修改构造函数
public ModifyObjectPropertyCommand(TextObject object,
String oldFontFamily, String newFontFamily,
double oldFontSize, double newFontSize,
String oldFontStyle, String newFontStyle) {
this.object = object;
this.oldFontFamily = oldFontFamily;
this.newFontFamily = newFontFamily;
this.oldFontSize = oldFontSize;
this.newFontSize = newFontSize;
this.oldFontStyle = oldFontStyle;
this.newFontStyle = newFontStyle;
this.propertyType = PropertyType.FONT;
}
// 文本颜色修改构造函数
public ModifyObjectPropertyCommand(TextObject object, String oldTextColor, String newTextColor) {
this.object = object;
this.oldTextColor = oldTextColor;
this.newTextColor = newTextColor;
this.propertyType = PropertyType.COLOR;
}
// 形状样式修改构造函数
public ModifyObjectPropertyCommand(ShapeObject object,
String oldFillColor, String newFillColor,
String oldStrokeColor, String newStrokeColor,
double oldStrokeWidth, double newStrokeWidth) {
this.object = object;
this.oldFillColor = oldFillColor;
this.newFillColor = newFillColor;
this.oldStrokeColor = oldStrokeColor;
this.newStrokeColor = newStrokeColor;
this.oldStrokeWidth = oldStrokeWidth;
this.newStrokeWidth = newStrokeWidth;
this.propertyType = PropertyType.SHAPE_STYLE;
}
// 旋转属性修改构造函数
public ModifyObjectPropertyCommand(DrawableObject object, double oldRotation, double newRotation) {
this.object = object;
this.oldRotation = oldRotation;
this.newRotation = newRotation;
this.propertyType = PropertyType.ROTATION;
}
@Override
public void execute() {
applyChanges(newText, newFontFamily, newFontSize, newFontStyle,
newTextColor, newFillColor, newStrokeColor, newStrokeWidth, newRotation);
}
@Override
public void undo() {
applyChanges(oldText, oldFontFamily, oldFontSize, oldFontStyle,
oldTextColor, oldFillColor, oldStrokeColor, oldStrokeWidth, oldRotation);
}
private void applyChanges(String text, String fontFamily, double fontSize, String fontStyle,
String textColor, String fillColor, String strokeColor,
double strokeWidth, double rotation) {
// 应用旋转(所有对象都有旋转属性)
object.setRotation(rotation);
// 根据对象类型应用其他属性
if (object instanceof TextObject) {
TextObject textObj = (TextObject) object;
if (propertyType == PropertyType.TEXT) {
textObj.setText(text);
} else if (propertyType == PropertyType.FONT) {
textObj.setFontFamily(fontFamily);
textObj.setFontSize(fontSize);
textObj.setFontStyle(fontStyle);
} else if (propertyType == PropertyType.COLOR) {
textObj.setTextColor(textColor);
}
} else if (object instanceof ShapeObject && propertyType == PropertyType.SHAPE_STYLE) {
ShapeObject shapeObj = (ShapeObject) object;
shapeObj.setFillColor(fillColor);
shapeObj.setStrokeColor(strokeColor);
shapeObj.setStrokeWidth(strokeWidth);
}
}
}
@@ -175,17 +175,6 @@ public class PropertyPanel extends VBox implements Initializable {
textContentField.setOnKeyReleased(e -> updateTextContent());
}
/**
* 更新旋转
*/
private void updateRotation() {
DrawableObject selected = canvas.getSelectedObject();
if (selected != null) {
selected.setRotation(rotationSlider.getValue());
canvas.redraw();
}
}
/**
* 显示文本控件
*/
@@ -258,10 +247,16 @@ public class PropertyPanel extends VBox implements Initializable {
private void updateTextContent() {
DrawableObject selected = canvas.getSelectedObject();
if (selected instanceof TextObject) {
((TextObject) selected).setText(textContentField.getText());
canvas.redraw();
TextObject textObj = (TextObject) selected;
String oldText = textObj.getText();
String newText = textContentField.getText();
if (!oldText.equals(newText) && canvas.getCommandHistory() != null) {
Command command = new ModifyObjectPropertyCommand(textObj, oldText, newText, 0);
canvas.getCommandHistory().execute(command);
}
}
}
/**
* 更新文本风格
@@ -270,80 +265,161 @@ public class PropertyPanel extends VBox implements Initializable {
DrawableObject selected = canvas.getSelectedObject();
if (selected instanceof TextObject) {
TextObject textObj = (TextObject) selected;
textObj.setFontFamily(fontFamilyCombo.getValue());
textObj.setFontSize(fontSizeSpinner.getValue());
textObj.setFontStyle(fontStyleCombo.getValue());
canvas.redraw();
String oldFontFamily = textObj.getFontFamily();
double oldFontSize = textObj.getFontSize();
String oldFontStyle = textObj.getFontStyle();
String newFontFamily = fontFamilyCombo.getValue();
double newFontSize = fontSizeSpinner.getValue();
String newFontStyle = fontStyleCombo.getValue();
if (!oldFontFamily.equals(newFontFamily) || oldFontSize != newFontSize ||
!oldFontStyle.equals(newFontStyle) && canvas.getCommandHistory() != null) {
Command command = new ModifyObjectPropertyCommand(
textObj, oldFontFamily, newFontFamily,
oldFontSize, newFontSize,
oldFontStyle, newFontStyle
);
canvas.getCommandHistory().execute(command);
}
}
}
/**
* 更新文本颜色
*/
private void updateTextColor() {
DrawableObject selected = canvas.getSelectedObject();
if (selected instanceof TextObject) {
if (selected instanceof TextObject && canvas.getCommandHistory() != null) {
TextObject textObj = (TextObject) selected;
String oldColor = textObj.getTextColor();
Color color = textColorPicker.getValue();
String hexColor = String.format("%02X%02X%02X",
String newColor = String.format("%02X%02X%02X",
(int) (color.getRed() * 255),
(int) (color.getGreen() * 255),
(int) (color.getBlue() * 255));
((TextObject) selected).setTextColor(hexColor);
if (!oldColor.equals(newColor)) {
Command command = new ModifyObjectPropertyCommand(textObj, oldColor, newColor);
canvas.getCommandHistory().execute(command);
canvas.redraw();
}
}
}
/**
* 更新填充颜色
*/
private void updateFillColor() {
DrawableObject selected = canvas.getSelectedObject();
if (selected instanceof ShapeObject) {
if (selected instanceof ShapeObject && canvas.getCommandHistory() != null) {
ShapeObject shapeObj = (ShapeObject) selected;
String oldFillColor = shapeObj.getFillColor();
Color color = fillColorPicker.getValue();
String hexColor = String.format("%02X%02X%02X",
String newFillColor = String.format("%02X%02X%02X",
(int) (color.getRed() * 255),
(int) (color.getGreen() * 255),
(int) (color.getBlue() * 255));
((ShapeObject) selected).setFillColor(hexColor);
if (!oldFillColor.equals(newFillColor)) {
Command command = new ModifyObjectPropertyCommand(
shapeObj,
oldFillColor, newFillColor,
shapeObj.getStrokeColor(), shapeObj.getStrokeColor(),
shapeObj.getStrokeWidth(), shapeObj.getStrokeWidth()
);
canvas.getCommandHistory().execute(command);
canvas.redraw();
}
}
}
/**
* 更新边框颜色
*/
private void updateStrokeColor() {
DrawableObject selected = canvas.getSelectedObject();
if (selected instanceof ShapeObject) {
if (selected instanceof ShapeObject && canvas.getCommandHistory() != null) {
ShapeObject shapeObj = (ShapeObject) selected;
String oldStrokeColor = shapeObj.getStrokeColor();
Color color = strokeColorPicker.getValue();
String hexColor = String.format("%02X%02X%02X",
String newStrokeColor = String.format("%02X%02X%02X",
(int) (color.getRed() * 255),
(int) (color.getGreen() * 255),
(int) (color.getBlue() * 255));
((ShapeObject) selected).setStrokeColor(hexColor);
if (!oldStrokeColor.equals(newStrokeColor)) {
Command command = new ModifyObjectPropertyCommand(
shapeObj,
shapeObj.getFillColor(), shapeObj.getFillColor(),
oldStrokeColor, newStrokeColor,
shapeObj.getStrokeWidth(), shapeObj.getStrokeWidth()
);
canvas.getCommandHistory().execute(command);
canvas.redraw();
}
}
}
/**
* 更新边框宽度
*/
private void updateStrokeWidth() {
DrawableObject selected = canvas.getSelectedObject();
if (selected instanceof ShapeObject) {
((ShapeObject) selected).setStrokeWidth(strokeWidthSpinner.getValue());
if (selected instanceof ShapeObject && canvas.getCommandHistory() != null) {
ShapeObject shapeObj = (ShapeObject) selected;
double oldWidth = shapeObj.getStrokeWidth();
double newWidth = strokeWidthSpinner.getValue();
if (Math.abs(oldWidth - newWidth) > 0.01) {
Command command = new ModifyObjectPropertyCommand(
shapeObj,
shapeObj.getFillColor(), shapeObj.getFillColor(),
shapeObj.getStrokeColor(), shapeObj.getStrokeColor(),
oldWidth, newWidth
);
canvas.getCommandHistory().execute(command);
canvas.redraw();
}
}
}
/**
* 更新旋转
*/
private void updateRotation() {
DrawableObject selected = canvas.getSelectedObject();
if (selected != null && canvas.getCommandHistory() != null) {
double oldRotation = selected.getRotation();
double newRotation = rotationSlider.getValue();
if (Math.abs(oldRotation - newRotation) > 0.01) {
Command command = new ModifyObjectPropertyCommand(selected, oldRotation, newRotation);
canvas.getCommandHistory().execute(command);
canvas.redraw();
}
}
}
/**
* 删除选中的对象
*/
private void deleteSelectedObject() {
DrawableObject selected = canvas.getSelectedObject();
if (selected != null) {
canvas.removeObject(selected);
updatePropertyPanel();
if (selected != null && canvas.getCommandHistory() != null) {
SlidePage currentPage = canvas.getCurrentPage();
if (currentPage != null) {
Command command = new DeleteObjectCommand(currentPage.getPageContent(), selected);
canvas.getCommandHistory().execute(command);
canvas.setSelectedObject(null);
canvas.redraw();
}
}
}
}