增添绘画元素的缩放功能,提示框和提示输入框中文化

This commit is contained in:
2025-11-24 14:55:33 +08:00
parent fbb84fe16b
commit 8a7d69df94
6 changed files with 181 additions and 26 deletions
@@ -1,5 +1,7 @@
package dev.bytevibe.hyperpoint; package dev.bytevibe.hyperpoint;
import dev.bytevibe.hyperpoint.Utils.MyAlert;
import dev.bytevibe.hyperpoint.Utils.MyTextInputDialog;
import javafx.event.ActionEvent; import javafx.event.ActionEvent;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.fxml.Initializable; import javafx.fxml.Initializable;
@@ -15,7 +17,7 @@ import java.util.ResourceBundle;
public class Controller implements Initializable { public class Controller implements Initializable {
@FXML @FXML
private Button openSlideButton; private Button newSlideButton;
@FXML @FXML
private Button newPageButton; private Button newPageButton;
@FXML @FXML
@@ -71,12 +73,12 @@ public class Controller implements Initializable {
} }
/** /**
* 打开幻灯片按钮的事件处理 * 新建幻灯片按钮的事件处理
*/ */
@FXML @FXML
public void onOpenSlide(ActionEvent actionEvent) { public void onNewSlide(ActionEvent actionEvent) {
TextInputDialog dialog = new TextInputDialog("我的幻灯片"); MyTextInputDialog dialog = new MyTextInputDialog("我的幻灯片");
dialog.setTitle("打开/创建幻灯片"); dialog.setTitle("创建幻灯片");
dialog.setHeaderText("请输入幻灯片名称"); dialog.setHeaderText("请输入幻灯片名称");
dialog.setContentText("幻灯片名称:"); dialog.setContentText("幻灯片名称:");
@@ -86,10 +88,14 @@ public class Controller implements Initializable {
currentSlide = new Slide(slideName); currentSlide = new Slide(slideName);
loadSlidePages(); loadSlidePages();
Alert alert = new Alert(Alert.AlertType.INFORMATION); MyAlert alert = new MyAlert(Alert.AlertType.INFORMATION);
alert.setTitle("成功"); alert.setTitle("成功");
alert.setHeaderText("幻灯片已打开"); alert.setHeaderText("幻灯片已创建");
alert.setContentText("幻灯片 \"" + slideName + "\"打开,共包含 " + currentSlide.getPages().size() + " 个页面"); alert.setContentText("幻灯片 \"" + slideName + "\"创建");
stage = (Stage) newSlideButton.getScene().getWindow();
if (stage != null) {
stage.setTitle("Hyperpoint - " + slideName);
}
alert.showAndWait(); alert.showAndWait();
} }
} }
@@ -155,7 +161,7 @@ public class Controller implements Initializable {
return; return;
} }
TextInputDialog dialog = new TextInputDialog("页面 " + (currentSlide.getPages().size() + 1)); MyTextInputDialog dialog = new MyTextInputDialog("页面 " + (currentSlide.getPages().size() + 1));
dialog.setTitle("新建页面"); dialog.setTitle("新建页面");
dialog.setHeaderText("请输入页面名称"); dialog.setHeaderText("请输入页面名称");
dialog.setContentText("页面名称:"); dialog.setContentText("页面名称:");
@@ -169,7 +175,7 @@ public class Controller implements Initializable {
pageListView.refresh(); pageListView.refresh();
pageListView.getSelectionModel().selectLast(); pageListView.getSelectionModel().selectLast();
Alert alert = new Alert(Alert.AlertType.INFORMATION); MyAlert alert = new MyAlert(Alert.AlertType.INFORMATION);
alert.setTitle("成功"); alert.setTitle("成功");
alert.setHeaderText("页面已创建"); alert.setHeaderText("页面已创建");
alert.setContentText("新页面 \"" + pageName + "\" 已添加。"); alert.setContentText("新页面 \"" + pageName + "\" 已添加。");
@@ -327,15 +333,12 @@ public class Controller implements Initializable {
*/ */
@FXML @FXML
public void logout(ActionEvent actionEvent) { public void logout(ActionEvent actionEvent) {
Alert alert = new Alert(Alert.AlertType.CONFIRMATION); MyAlert alert = new MyAlert(Alert.AlertType.CONFIRMATION);
alert.setTitle("退出"); alert.setTitle("退出");
alert.setHeaderText("您确定要退出吗?"); alert.setHeaderText("您确定要退出吗?");
alert.setContentText("点击确定退出,点击取消返回。"); alert.setContentText("点击确定退出,点击取消返回。");
ButtonType confirm = new ButtonType("确定", ButtonBar.ButtonData.OK_DONE);
ButtonType cancel = new ButtonType("取消", ButtonBar.ButtonData.CANCEL_CLOSE);
alert.getButtonTypes().setAll(confirm, cancel);
if (alert.showAndWait().orElse(null) == confirm) { if (alert.showAndWait().orElse(null) == MyAlert.isOK()) {
stage = (Stage) logout.getScene().getWindow(); stage = (Stage) logout.getScene().getWindow();
stage.close(); stage.close();
} }
@@ -14,12 +14,22 @@ import javafx.scene.text.FontWeight;
* 绘图Canvas组件,用于渲染和交互所有可绘制对象 * 绘图Canvas组件,用于渲染和交互所有可绘制对象
*/ */
public class DrawingCanvas extends Pane { public class DrawingCanvas extends Pane {
// 缩放点的枚举
enum ResizePoint {
TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT, BOTTOM_RIGHT, NONE
}
private Canvas canvas; private Canvas canvas;
private PageContent pageContent; private PageContent pageContent;
private DrawableObject selectedObject; private DrawableObject selectedObject;
private double lastX, lastY; private double lastX, lastY;
private Runnable onSelectionChanged; private Runnable onSelectionChanged;
// 缩放点有关的属性
private ResizePoint resizePoint = ResizePoint.NONE;
// 缩放点大小
private static final double HANDLE_SIZE = 8;
public DrawingCanvas(PageContent pageContent) { public DrawingCanvas(PageContent pageContent) {
this.pageContent = pageContent; this.pageContent = pageContent;
this.canvas = new Canvas(); this.canvas = new Canvas();
@@ -54,10 +64,21 @@ public class DrawingCanvas extends Pane {
lastX = event.getX(); lastX = event.getX();
lastY = event.getY(); lastY = event.getY();
// 如果已经有选中对象,先检查是否点击在调整点上
if (selectedObject != null) {
resizePoint = getResizePointAt(lastX, lastY, selectedObject);
if (resizePoint != ResizePoint.NONE) {
// 点击在调整点上,进入缩放模式
return;
}
}
// 重置缩放模式
resizePoint = ResizePoint.NONE;
// 查找被点击的对象 // 查找被点击的对象
DrawableObject clicked = pageContent.findObjectAt(lastX, lastY); DrawableObject clicked = pageContent.findObjectAt(lastX, lastY);
// 如果点击在已选中对象上,保持选中状态
if (clicked == null) { if (clicked == null) {
setSelectedObject(null); setSelectedObject(null);
} else { } else {
@@ -67,6 +88,40 @@ public class DrawingCanvas extends Pane {
redraw(); redraw();
} }
/**
* 获取点击位置对应的调整点
*/
private ResizePoint getResizePointAt(double x, double y, DrawableObject obj) {
double handleSize = HANDLE_SIZE;
double objX = obj.getX();
double objY = obj.getY();
double objW = obj.getWidth();
double objH = obj.getHeight();
// 检查左上角
if (x >= objX - handleSize && x <= objX + handleSize &&
y >= objY - handleSize && y <= objY + handleSize) {
return ResizePoint.TOP_LEFT;
}
// 检查右上角
if (x >= objX + objW - handleSize && x <= objX + objW + handleSize &&
y >= objY - handleSize && y <= objY + handleSize) {
return ResizePoint.TOP_RIGHT;
}
// 检查左下角
if (x >= objX - handleSize && x <= objX + handleSize &&
y >= objY + objH - handleSize && y <= objY + objH + handleSize) {
return ResizePoint.BOTTOM_LEFT;
}
// 检查右下角
if (x >= objX + objW - handleSize && x <= objX + objW + handleSize &&
y >= objY + objH - handleSize && y <= objY + objH + handleSize) {
return ResizePoint.BOTTOM_RIGHT;
}
return ResizePoint.NONE;
}
/** /**
* 鼠标拖动事件处理 * 鼠标拖动事件处理
*/ */
@@ -75,9 +130,14 @@ public class DrawingCanvas extends Pane {
double dx = event.getX() - lastX; double dx = event.getX() - lastX;
double dy = event.getY() - lastY; double dy = event.getY() - lastY;
// 更新选中对象的位置 // 如果正在缩放
selectedObject.setX(selectedObject.getX() + dx); if (resizePoint != ResizePoint.NONE) {
selectedObject.setY(selectedObject.getY() + dy); resizeObject(selectedObject, dx, dy, resizePoint);
} else {
// 移动对象
selectedObject.setX(selectedObject.getX() + dx);
selectedObject.setY(selectedObject.getY() + dy);
}
lastX = event.getX(); lastX = event.getX();
lastY = event.getY(); lastY = event.getY();
@@ -86,13 +146,58 @@ public class DrawingCanvas extends Pane {
} }
} }
/**
* 缩放对象
*/
private void resizeObject(DrawableObject obj, double dx, double dy, ResizePoint point) {
// 最小尺寸限制
final double MIN_SIZE = 20;
switch (point) {
case TOP_LEFT:
// 从左上角缩放:x和y增加,width和height减少
if (obj.getWidth() - dx >= MIN_SIZE && obj.getHeight() - dy >= MIN_SIZE) {
obj.setX(obj.getX() + dx);
obj.setY(obj.getY() + dy);
obj.setWidth(obj.getWidth() - dx);
obj.setHeight(obj.getHeight() - dy);
}
break;
case TOP_RIGHT:
// 从右上角缩放:y增加,width增加,height减少
if (obj.getWidth() + dx >= MIN_SIZE && obj.getHeight() - dy >= MIN_SIZE) {
obj.setY(obj.getY() + dy);
obj.setWidth(obj.getWidth() + dx);
obj.setHeight(obj.getHeight() - dy);
}
break;
case BOTTOM_LEFT:
// 从左下角缩放:x增加,width减少,height增加
if (obj.getWidth() - dx >= MIN_SIZE && obj.getHeight() + dy >= MIN_SIZE) {
obj.setX(obj.getX() + dx);
obj.setWidth(obj.getWidth() - dx);
obj.setHeight(obj.getHeight() + dy);
}
break;
case BOTTOM_RIGHT:
// 从右下角缩放:width和height增加
if (obj.getWidth() + dx >= MIN_SIZE && obj.getHeight() + dy >= MIN_SIZE) {
obj.setWidth(obj.getWidth() + dx);
obj.setHeight(obj.getHeight() + dy);
}
break;
default:
break;
}
}
/** /**
* 鼠标释放事件处理 * 鼠标释放事件处理
*/ */
private void handleMouseReleased(MouseEvent event) { private void handleMouseReleased(MouseEvent event) {
// 可以在这里添加其他逻辑,如取消选中等 // 释放鼠标时,重置缩放模式
resizePoint = ResizePoint.NONE;
} }
/** /**
@@ -2,6 +2,7 @@ package dev.bytevibe.hyperpoint;
import dev.bytevibe.hyperpoint.Utils.MyAlert;
import javafx.application.Application; import javafx.application.Application;
import javafx.fxml.FXMLLoader; import javafx.fxml.FXMLLoader;
import javafx.scene.Parent; import javafx.scene.Parent;
@@ -9,6 +10,7 @@ import javafx.scene.Scene;
import javafx.scene.control.Alert; import javafx.scene.control.Alert;
import javafx.scene.control.ButtonBar; import javafx.scene.control.ButtonBar;
import javafx.scene.control.ButtonType; import javafx.scene.control.ButtonType;
import javafx.scene.image.Image;
import javafx.stage.Stage; import javafx.stage.Stage;
public class Main extends Application { public class Main extends Application {
@@ -18,6 +20,10 @@ public class Main extends Application {
Parent root = FXMLLoader.load(getClass().getResource("main.fxml")); Parent root = FXMLLoader.load(getClass().getResource("main.fxml"));
Scene scene = new Scene(root, 1200, 600); Scene scene = new Scene(root, 1200, 600);
stage.setScene(scene); stage.setScene(scene);
Image icon = new Image(getClass().getResourceAsStream("icon.png"));
stage.setTitle("Hyperpoint");
stage.getIcons().add(icon);
stage.show(); stage.show();
stage.setOnCloseRequest(event -> {this.logout(stage);}); stage.setOnCloseRequest(event -> {this.logout(stage);});
@@ -29,15 +35,12 @@ public class Main extends Application {
// 窗口退出键对应的action // 窗口退出键对应的action
public void logout(Stage stage) { public void logout(Stage stage) {
Alert alert = new Alert(Alert.AlertType.CONFIRMATION); MyAlert alert = new MyAlert(Alert.AlertType.CONFIRMATION);
alert.setTitle("退出登录"); alert.setTitle("退出登录");
alert.setHeaderText("您确定要退出登录吗?"); alert.setHeaderText("您确定要退出登录吗?");
alert.setContentText("点击确定退出登录,点击取消返回。"); alert.setContentText("点击确定退出登录,点击取消返回。");
ButtonType confirm = new ButtonType("确定", ButtonBar.ButtonData.OK_DONE);
ButtonType cancel = new ButtonType("取消", ButtonBar.ButtonData.CANCEL_CLOSE);
alert.getButtonTypes().setAll(confirm, cancel);
if (alert.showAndWait().orElse(null) == confirm) { if (alert.showAndWait().orElse(null) == MyAlert.isOK()) {
stage.close(); stage.close();
} }
} }
@@ -0,0 +1,24 @@
package dev.bytevibe.hyperpoint.Utils;
import javafx.scene.control.Alert;
import javafx.scene.control.ButtonBar;
import javafx.scene.control.ButtonType;
// 提示框,按钮设置为中文
public class MyAlert extends Alert {
private static ButtonType confirm = new ButtonType("确定", ButtonBar.ButtonData.OK_DONE);
private static ButtonType cancel = new ButtonType("取消", ButtonBar.ButtonData.CANCEL_CLOSE);
public MyAlert(Alert.AlertType alertType) {
super(alertType);
if (alertType == Alert.AlertType.CONFIRMATION) {
getDialogPane().getButtonTypes().setAll(confirm, cancel);
} else if (alertType == Alert.AlertType.INFORMATION || alertType == Alert.AlertType.WARNING || alertType == Alert.AlertType.ERROR) {
getDialogPane().getButtonTypes().setAll(confirm);
}
}
public static ButtonType isOK() {
return confirm;
}
}
@@ -0,0 +1,20 @@
package dev.bytevibe.hyperpoint.Utils;
import javafx.scene.control.ButtonBar;
import javafx.scene.control.ButtonType;
import javafx.scene.control.TextInputDialog;
// 提示输入框,按钮设置为中文
public class MyTextInputDialog extends TextInputDialog {
private static ButtonType confirm = new ButtonType("确定", ButtonBar.ButtonData.OK_DONE);
private static ButtonType cancel = new ButtonType("取消", ButtonBar.ButtonData.CANCEL_CLOSE);
public MyTextInputDialog(String defaultValue) {
super(defaultValue);
getDialogPane().getButtonTypes().setAll(confirm, cancel);
}
public static ButtonType isOK() {
return confirm;
}
}
@@ -14,7 +14,7 @@
<children> <children>
<HBox spacing="5" style="-fx-padding: 5;"> <HBox spacing="5" style="-fx-padding: 5;">
<children> <children>
<Button fx:id="openSlideButton" mnemonicParsing="false" onAction="#onOpenSlide" text="打开幻灯片" /> <Button fx:id="newSlideButton" mnemonicParsing="false" onAction="#onNewSlide" text="新建幻灯片" />
<Button fx:id="newPageButton" mnemonicParsing="false" onAction="#onNewPage" text="新建页面" /> <Button fx:id="newPageButton" mnemonicParsing="false" onAction="#onNewPage" text="新建页面" />
<Button fx:id="deletePageButton" mnemonicParsing="false" onAction="#onDeletePage" text="删除页面" /> <Button fx:id="deletePageButton" mnemonicParsing="false" onAction="#onDeletePage" text="删除页面" />
<Label text=" | " /> <Label text=" | " />