parent
f0cc080a5e
commit
a6cbd4b341
|
@ -0,0 +1,41 @@
|
|||
package org.rococy.roomit.control;
|
||||
|
||||
import javafx.scene.Group;
|
||||
import javafx.scene.Node;
|
||||
|
||||
/**
|
||||
* 存放canvas的容器
|
||||
*
|
||||
* @author Rococy
|
||||
* @date 2022/9/17
|
||||
*/
|
||||
public class CanvasGroup extends Group {
|
||||
|
||||
/**
|
||||
* canvas配置
|
||||
*/
|
||||
private static final int TRANSPARENT_CANVAS_COUNT = 5;
|
||||
private static boolean isTransparent = true;
|
||||
|
||||
public CanvasGroup() {
|
||||
initCanvas();
|
||||
}
|
||||
|
||||
private void initCanvas() {
|
||||
if (isTransparent) {
|
||||
// 初始化层叠Canvas
|
||||
for (int i = 0; i < TRANSPARENT_CANVAS_COUNT; i++) {
|
||||
RoomItCanvas canvas = new RoomItCanvas(isTransparent);
|
||||
canvas.setViewOrder(i);
|
||||
this.addChildren(canvas);
|
||||
}
|
||||
} else {
|
||||
// 直接给一个Canvas即可
|
||||
this.addChildren(new RoomItCanvas(isTransparent));
|
||||
}
|
||||
}
|
||||
|
||||
public void addChildren(Node node) {
|
||||
this.getChildren().add(node);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,152 @@
|
|||
package org.rococy.roomit.control;
|
||||
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.input.MouseEvent;
|
||||
import javafx.scene.shape.Ellipse;
|
||||
import org.rococy.roomit.control.base.Resizer;
|
||||
|
||||
/**
|
||||
* @author Rococy
|
||||
* @date 2022/9/18
|
||||
*/
|
||||
public class ResizableEllipseWrapper extends Resizer {
|
||||
|
||||
/**
|
||||
* 配置项
|
||||
*/
|
||||
private static final int BORDER_WIDTH = 2;
|
||||
private static final String BORDER_COLOR = "linear-gradient(to bottom, #f64f5988, #c471ed88, #12c2e988);";
|
||||
|
||||
/**
|
||||
* 内部椭圆
|
||||
*/
|
||||
private final InnerEllipse innerEllipse = new InnerEllipse();
|
||||
|
||||
/**
|
||||
* 与内部椭圆的间隔距离
|
||||
*/
|
||||
private static final int ELLIPSE_INTERVALS = 3;
|
||||
|
||||
/**
|
||||
* @param originX 在整个屏幕内的初始x值
|
||||
* @param originY 在整个屏幕内的初始y值
|
||||
*/
|
||||
public ResizableEllipseWrapper(double originX, double originY) {
|
||||
super(originX, originY);
|
||||
|
||||
// 设置样式
|
||||
this.setStyle(String.format("-fx-border-width: %spx; -fx-border-style:solid; -fx-border-color: %s; -fx-border-radius: %s;", BORDER_WIDTH, BORDER_COLOR, 4));
|
||||
// 添加内椭圆
|
||||
this.addChildren(innerEllipse);
|
||||
|
||||
// 初始化事件
|
||||
initEvents();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected double getBorderWidth() {
|
||||
return BORDER_WIDTH;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取内部椭圆
|
||||
*
|
||||
* @return 椭圆
|
||||
*/
|
||||
public Ellipse getInnerEllipse() {
|
||||
return innerEllipse;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取矩形与内部椭圆的间隔距离
|
||||
*
|
||||
* @return 间隔距离
|
||||
*/
|
||||
public int getEllipseIntervals() {
|
||||
return BORDER_WIDTH + ELLIPSE_INTERVALS;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加子元素
|
||||
*
|
||||
* @param node Node元素
|
||||
*/
|
||||
public void addChildren(Node node) {
|
||||
this.getChildren().add(node);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置样式
|
||||
*/
|
||||
private void setBorderWidth(int borderWidth) {
|
||||
super.setStyle(String.format("-fx-border-width: %spx; -fx-border-style:solid; -fx-border-color: %s; -fx-border-radius: %s;", borderWidth, BORDER_COLOR, 4));
|
||||
}
|
||||
|
||||
private void showBorder() {
|
||||
this.setBorderWidth(BORDER_WIDTH);
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化事件
|
||||
*/
|
||||
private void initEvents() {
|
||||
// 鼠标进入
|
||||
bindMouseEnterEvent();
|
||||
// 鼠标退出
|
||||
bindMouseExistedEvent();
|
||||
// 拓展鼠标拖拽事件
|
||||
bindExtraMouseDraggedEvent();
|
||||
}
|
||||
|
||||
/**
|
||||
* 鼠标进入事件,鼠标进入显示边框线
|
||||
*/
|
||||
private void bindMouseEnterEvent() {
|
||||
this.addEventHandler(MouseEvent.MOUSE_ENTERED, e -> showBorder());
|
||||
}
|
||||
|
||||
/**
|
||||
* 鼠标退出事件,鼠标进入隐藏边框线
|
||||
*/
|
||||
private void bindMouseExistedEvent() {
|
||||
this.addEventHandler(MouseEvent.MOUSE_EXITED, e -> this.setBorderWidth(0));
|
||||
}
|
||||
|
||||
/**
|
||||
* 拓展鼠标拖拽事件
|
||||
*/
|
||||
private void bindExtraMouseDraggedEvent() {
|
||||
this.addEventHandler(MouseEvent.MOUSE_DRAGGED, e -> {
|
||||
// 拖拽也要显示border
|
||||
this.showBorder();
|
||||
|
||||
double centerX = this.getPrefWidth() / 2;
|
||||
double centerY = this.getPrefHeight() / 2;
|
||||
|
||||
innerEllipse.setCenterX(centerX);
|
||||
innerEllipse.setCenterY(centerY);
|
||||
|
||||
innerEllipse.setRadiusX(centerX - this.getEllipseIntervals());
|
||||
innerEllipse.setRadiusY(centerY - this.getEllipseIntervals());
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 矩形内部的椭圆
|
||||
*/
|
||||
private static class InnerEllipse extends Ellipse {
|
||||
|
||||
/**
|
||||
* 配置项
|
||||
*/
|
||||
private static final String FILL_COLOR = "#00000000";
|
||||
private static final String STROKE_COLOR = "linear-gradient(to bottom, #f64f59, #c471ed, #12c2e9);";
|
||||
private static final int BORDER_WIDTH = 3;
|
||||
|
||||
public InnerEllipse() {
|
||||
this.setStyle(String.format("-fx-fill: %s; -fx-stroke: %s; -fx-stroke-width: %d", FILL_COLOR, STROKE_COLOR, BORDER_WIDTH));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,239 +1,43 @@
|
|||
package org.rococy.roomit.control;
|
||||
|
||||
import javafx.scene.Cursor;
|
||||
import javafx.scene.paint.Paint;
|
||||
import javafx.scene.shape.Rectangle;
|
||||
import org.rococy.roomit.enums.RectangleCtrl;
|
||||
import org.rococy.roomit.control.base.Resizer;
|
||||
|
||||
/**
|
||||
* 能改变尺寸的矩形
|
||||
*
|
||||
* @author Rococy
|
||||
* @date 2022/9/14
|
||||
* @date 2022/9/19
|
||||
*/
|
||||
public class ResizableRectangle extends Rectangle {
|
||||
|
||||
/**
|
||||
* 矩形原点
|
||||
*/
|
||||
private double originX, originY;
|
||||
|
||||
/**
|
||||
* 记录调整完矩形后的大小
|
||||
*/
|
||||
private double width, height;
|
||||
|
||||
/**
|
||||
* 当处于移动状态时,记录的xy值
|
||||
*/
|
||||
private double moveX, moveY;
|
||||
|
||||
/**
|
||||
* 矩形操作类型
|
||||
*/
|
||||
private RectangleCtrl rectangleCtrl;
|
||||
public class ResizableRectangle extends Resizer {
|
||||
|
||||
/**
|
||||
* 配置项
|
||||
*/
|
||||
private static final String COLOR = "#f00";
|
||||
private static final String FILL_COLOR = "#00000000";
|
||||
private static final String STROKE_COLOR = "linear-gradient(to bottom, #f64f59, #c471ed, #12c2e9)";
|
||||
private static final double BORDER_WIDTH = 3;
|
||||
private static final String BORDER_RADIUS = "5px";
|
||||
|
||||
/**
|
||||
* @param originX 在整个屏幕内的x值
|
||||
* @param originY 在整个屏幕内的y值
|
||||
* 最小宽高
|
||||
*/
|
||||
private static final double MIN_WIDTH = 8, MIN_HEIGHT = 8;
|
||||
|
||||
/**
|
||||
* @param originX 在整个屏幕内的初始x值
|
||||
* @param originY 在整个屏幕内的初始y值
|
||||
*/
|
||||
public ResizableRectangle(double originX, double originY) {
|
||||
// 记录原点
|
||||
this.originX = originX;
|
||||
this.originY = originY;
|
||||
super(originX, originY);
|
||||
|
||||
// 填充透明色,边框颜色,边框宽度
|
||||
this.setFill(Paint.valueOf("#00000000"));
|
||||
this.setStroke(Paint.valueOf(COLOR));
|
||||
this.setStrokeWidth(BORDER_WIDTH);
|
||||
|
||||
// 初始化调整大小事件
|
||||
this.initEvents();
|
||||
// 填充颜色、边框颜色、边框宽度、圆角
|
||||
this.setStyle(String.format("-fx-fill: %s; -fx-border-color: %s; -fx-border-width: %spx; -fx-border-style:solid; -fx-border-radius: %s;", FILL_COLOR, STROKE_COLOR, BORDER_WIDTH, BORDER_RADIUS));
|
||||
this.setMinSize(MIN_WIDTH, MIN_HEIGHT);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 初始化矩形调整大小事件
|
||||
*/
|
||||
public void initEvents() {
|
||||
bindMousePressedEvent();
|
||||
bindMouseMovedEvent();
|
||||
bindMouseDraggedEvent();
|
||||
bindMouseReleasedEvent();
|
||||
@Override
|
||||
protected double getBorderWidth() {
|
||||
return BORDER_WIDTH;
|
||||
}
|
||||
|
||||
/**
|
||||
* 鼠标按下
|
||||
*/
|
||||
private void bindMousePressedEvent() {
|
||||
this.setOnMousePressed(e -> {
|
||||
width = this.getWidth();
|
||||
height = this.getHeight();
|
||||
|
||||
if (rectangleCtrl == RectangleCtrl.MOVE) {
|
||||
moveX = e.getScreenX() - this.getLayoutX();
|
||||
moveY = e.getScreenY() - this.getLayoutY();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 鼠标移动
|
||||
*/
|
||||
private void bindMouseMovedEvent() {
|
||||
this.setOnMouseMoved(e -> {
|
||||
double width = this.getWidth(),
|
||||
height = this.getHeight(),
|
||||
x = e.getScreenX() - this.getLayoutX(),
|
||||
y = e.getScreenY() - this.getLayoutY();
|
||||
|
||||
|
||||
// topLeft
|
||||
if (x <= 3 && y <= 3) {
|
||||
this.setCursor(Cursor.SE_RESIZE);
|
||||
rectangleCtrl = RectangleCtrl.TOP_LEFT;
|
||||
return;
|
||||
}
|
||||
|
||||
// topMiddle
|
||||
if (x <= width - 3 && y <= 3) {
|
||||
this.setCursor(Cursor.N_RESIZE);
|
||||
rectangleCtrl = RectangleCtrl.TOP_MIDDLE;
|
||||
return;
|
||||
}
|
||||
|
||||
// topRight
|
||||
if (x <= width && y <= 3) {
|
||||
this.setCursor(Cursor.NE_RESIZE);
|
||||
rectangleCtrl = RectangleCtrl.TOP_RIGHT;
|
||||
return;
|
||||
}
|
||||
|
||||
// centerLeft
|
||||
if (x <= 3 && y <= height - 3) {
|
||||
this.setCursor(Cursor.W_RESIZE);
|
||||
rectangleCtrl = RectangleCtrl.CENTER_LEFT;
|
||||
return;
|
||||
}
|
||||
|
||||
// bottomLeft
|
||||
if (x <= 3 && y <= height) {
|
||||
this.setCursor(Cursor.NE_RESIZE);
|
||||
rectangleCtrl = RectangleCtrl.BOTTOM_LEFT;
|
||||
return;
|
||||
}
|
||||
|
||||
// bottomMiddle
|
||||
if (x <= width - 3 && y >= height - 3) {
|
||||
this.setCursor(Cursor.N_RESIZE);
|
||||
rectangleCtrl = RectangleCtrl.BOTTOM_MIDDLE;
|
||||
return;
|
||||
}
|
||||
|
||||
// bottomRight
|
||||
if (x <= width && y >= height - 3) {
|
||||
this.setCursor(Cursor.SE_RESIZE);
|
||||
rectangleCtrl = RectangleCtrl.BOTTOM_RIGHT;
|
||||
return;
|
||||
}
|
||||
|
||||
// centerRight
|
||||
if (x >= width - 3 && y <= height) {
|
||||
this.setCursor(Cursor.W_RESIZE);
|
||||
rectangleCtrl = RectangleCtrl.CENTER_RIGHT;
|
||||
return;
|
||||
}
|
||||
|
||||
// 移动指针
|
||||
if (x >= 3 + 1 && x <= width - 3 && y >= 3 + 1 && y <= height - 3) {
|
||||
this.setCursor(Cursor.MOVE);
|
||||
rectangleCtrl = RectangleCtrl.MOVE;
|
||||
return;
|
||||
}
|
||||
|
||||
this.setCursor(Cursor.DEFAULT);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 鼠标拖拽
|
||||
*/
|
||||
private void bindMouseDraggedEvent() {
|
||||
this.setOnMouseDragged(e -> {
|
||||
// 防止快速操作
|
||||
if (rectangleCtrl == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
double screenX = e.getScreenX(),
|
||||
screenY = e.getScreenY(),
|
||||
x = screenX - originX,
|
||||
y = screenY - originY;
|
||||
|
||||
|
||||
switch (rectangleCtrl) {
|
||||
case TOP_LEFT -> {
|
||||
this.setLayoutX(screenX);
|
||||
this.setLayoutY(screenY);
|
||||
|
||||
this.setWidth(width - x);
|
||||
this.setHeight(height - y);
|
||||
}
|
||||
|
||||
case TOP_MIDDLE -> {
|
||||
this.setLayoutY(screenY);
|
||||
this.setHeight(height - y);
|
||||
}
|
||||
|
||||
case TOP_RIGHT -> {
|
||||
this.setLayoutY(screenY);
|
||||
|
||||
this.setWidth(x);
|
||||
this.setHeight(height - y);
|
||||
}
|
||||
|
||||
case CENTER_LEFT -> {
|
||||
this.setLayoutX(screenX);
|
||||
this.setWidth(width - x);
|
||||
}
|
||||
|
||||
case CENTER_RIGHT -> this.setWidth(x);
|
||||
|
||||
case BOTTOM_LEFT -> {
|
||||
this.setLayoutX(screenX);
|
||||
this.setWidth(width - x);
|
||||
this.setHeight(y);
|
||||
}
|
||||
|
||||
case BOTTOM_MIDDLE -> this.setHeight(y);
|
||||
|
||||
case BOTTOM_RIGHT -> {
|
||||
this.setWidth(x);
|
||||
this.setHeight(y);
|
||||
}
|
||||
|
||||
case MOVE -> {
|
||||
this.setLayoutX(screenX - moveX);
|
||||
this.setLayoutY(screenY - moveY);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 鼠标抬起
|
||||
*/
|
||||
private void bindMouseReleasedEvent() {
|
||||
this.setOnMouseReleased(e -> {
|
||||
this.originX = this.getLayoutX();
|
||||
this.originY = this.getLayoutY();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,182 @@
|
|||
package org.rococy.roomit.control;
|
||||
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.canvas.Canvas;
|
||||
import javafx.scene.canvas.GraphicsContext;
|
||||
import javafx.scene.paint.Paint;
|
||||
import javafx.scene.shape.StrokeLineCap;
|
||||
import javafx.scene.shape.StrokeLineJoin;
|
||||
import org.rococy.roomit.util.ScreenUtils;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
/**
|
||||
* 自动透明的Canvas
|
||||
*
|
||||
* @author Rococy
|
||||
* @date 2022/9/13
|
||||
*/
|
||||
public class RoomItCanvas extends Canvas {
|
||||
|
||||
/**
|
||||
* 是否透明
|
||||
*/
|
||||
private final boolean isTransparent;
|
||||
|
||||
/**
|
||||
* 透明度初始值为1
|
||||
*/
|
||||
private double opacity = 1;
|
||||
|
||||
/**
|
||||
* 是否可用(是否可以切换到顶层)
|
||||
*/
|
||||
private boolean used = true;
|
||||
|
||||
/**
|
||||
* 画笔
|
||||
*/
|
||||
private GraphicsContext gc;
|
||||
|
||||
/**
|
||||
* 记录画笔开始画的位置
|
||||
*/
|
||||
private double graphicStartX, graphicStartY;
|
||||
|
||||
public RoomItCanvas(boolean isTransparent) {
|
||||
// 初始化宽高
|
||||
super(ScreenUtils.getScreenWidth(), ScreenUtils.getScreenHeight());
|
||||
this.isTransparent = isTransparent;
|
||||
// 初始化画笔
|
||||
initGraphics();
|
||||
// 初始化事件
|
||||
initEvents();
|
||||
}
|
||||
|
||||
/**
|
||||
* 开始慢慢变透明
|
||||
*/
|
||||
public void startTransparency() {
|
||||
used = false;
|
||||
new Timer().schedule(new OpacityTask(), 0, 100);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回是否可用(透明度是否已经从0归1)
|
||||
*
|
||||
* @return 是否可用
|
||||
*/
|
||||
public boolean isUsed() {
|
||||
return used;
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化画笔
|
||||
*/
|
||||
private void initGraphics() {
|
||||
gc = this.getGraphicsContext2D();
|
||||
// 画笔颜色
|
||||
gc.setStroke(Paint.valueOf("#f00"));
|
||||
// 让线变得圆滑
|
||||
gc.setLineCap(StrokeLineCap.ROUND);
|
||||
gc.setLineJoin(StrokeLineJoin.ROUND);
|
||||
// 线条宽度
|
||||
gc.setLineWidth(5);
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化事件
|
||||
*/
|
||||
private void initEvents() {
|
||||
this.bindMousePressedEvent();
|
||||
this.bindMouseDraggedEvent();
|
||||
|
||||
if (isTransparent) {
|
||||
this.bindMouseReleasedEvent();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 鼠标按下
|
||||
*/
|
||||
private void bindMousePressedEvent() {
|
||||
this.setOnMousePressed(e -> {
|
||||
graphicStartX = e.getScreenX();
|
||||
graphicStartY = e.getScreenY();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 鼠标拖拽
|
||||
*/
|
||||
private void bindMouseDraggedEvent() {
|
||||
// 鼠标按下并拖动
|
||||
this.setOnMouseDragged(e -> {
|
||||
double endX = e.getX();
|
||||
double endY = e.getY();
|
||||
|
||||
// 画线
|
||||
gc.strokeLine(graphicStartX, graphicStartY, endX, endY);
|
||||
|
||||
// 连续画线
|
||||
graphicStartX = endX;
|
||||
graphicStartY = endY;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 鼠标抬起
|
||||
*/
|
||||
private void bindMouseReleasedEvent() {
|
||||
this.setOnMouseReleased(e -> {
|
||||
// 当前画完的Canvas开始变透明
|
||||
this.startTransparency();
|
||||
|
||||
// 获取相邻的TransparentCanvas
|
||||
CanvasGroup group = (CanvasGroup) getParent();
|
||||
List<Node> nodeList = group.getChildren();
|
||||
|
||||
|
||||
for (Node node : nodeList) {
|
||||
// 即将置于顶层的canvas
|
||||
RoomItCanvas topCanvas = (RoomItCanvas) node;
|
||||
|
||||
// 正在隐藏当中
|
||||
if (!topCanvas.isUsed() || topCanvas == this) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 交换图形层叠位置
|
||||
this.setViewOrder(topCanvas.getViewOrder());
|
||||
topCanvas.setViewOrder(0);
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 透明定时线程
|
||||
*/
|
||||
private class OpacityTask extends TimerTask {
|
||||
|
||||
private final RoomItCanvas canvas = RoomItCanvas.this;
|
||||
|
||||
private static final double MIN_OPACITY = 0.1;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
opacity *= 0.9;
|
||||
canvas.setOpacity(opacity);
|
||||
|
||||
if (opacity < MIN_OPACITY) {
|
||||
opacity = 1;
|
||||
canvas.getGraphicsContext2D().clearRect(0, 0, canvas.getWidth(), canvas.getHeight());
|
||||
canvas.setOpacity(opacity);
|
||||
used = true;
|
||||
this.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package org.rococy.roomit.control;
|
||||
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.layout.Pane;
|
||||
import org.rococy.roomit.util.ScreenUtils;
|
||||
|
||||
/**
|
||||
* 操作画矩形、圆形的面板
|
||||
*
|
||||
* @author Rococy
|
||||
* @date 2022/9/17
|
||||
*/
|
||||
public class ShapePane extends Pane {
|
||||
|
||||
public ShapePane() {
|
||||
this.setPrefSize(ScreenUtils.getScreenWidth(), ScreenUtils.getScreenHeight());
|
||||
}
|
||||
|
||||
public void addChildren(Node node) {
|
||||
this.getChildren().add(node);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,250 @@
|
|||
package org.rococy.roomit.control.base;
|
||||
|
||||
import javafx.scene.Cursor;
|
||||
import javafx.scene.input.MouseEvent;
|
||||
import javafx.scene.layout.Pane;
|
||||
import org.rococy.roomit.enums.RectangleCtrl;
|
||||
|
||||
/**
|
||||
* 能改变尺寸的容器
|
||||
*
|
||||
* @author Rococy
|
||||
* @date 2022/9/14
|
||||
*/
|
||||
public abstract class Resizer extends Pane {
|
||||
|
||||
/**
|
||||
* 矩形原点
|
||||
*/
|
||||
private double originX, originY;
|
||||
|
||||
/**
|
||||
* 记录调整完矩形后的大小
|
||||
*/
|
||||
private double width, height;
|
||||
|
||||
/**
|
||||
* 当处于移动状态时,记录的xy值
|
||||
*/
|
||||
private double moveX, moveY;
|
||||
|
||||
/**
|
||||
* 矩形操作类型
|
||||
*/
|
||||
private RectangleCtrl rectangleCtrl;
|
||||
|
||||
/**
|
||||
* 边框宽度
|
||||
*/
|
||||
private final double borderWidth = this.getBorderWidth();
|
||||
|
||||
/**
|
||||
* @param originX 在整个屏幕内的初始x值
|
||||
* @param originY 在整个屏幕内的初始y值
|
||||
*/
|
||||
public Resizer(double originX, double originY) {
|
||||
// 记录原点
|
||||
this.originX = originX;
|
||||
this.originY = originY;
|
||||
|
||||
// 初始化调整大小事件
|
||||
this.initEvents();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取边框宽度
|
||||
*
|
||||
* @return 边框宽度
|
||||
*/
|
||||
protected abstract double getBorderWidth();
|
||||
|
||||
/**
|
||||
* 初始化矩形调整大小事件
|
||||
*/
|
||||
private void initEvents() {
|
||||
this.bindMouseEnterEvent();
|
||||
this.bindMousePressedEvent();
|
||||
this.bindMouseMovedEvent();
|
||||
this.bindMouseDraggedEvent();
|
||||
this.bindMouseReleasedEvent();
|
||||
|
||||
this.bindKeyPressedEvent();
|
||||
}
|
||||
|
||||
/**
|
||||
* 鼠标进入
|
||||
*/
|
||||
private void bindMouseEnterEvent() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 鼠标按下
|
||||
*/
|
||||
private void bindMousePressedEvent() {
|
||||
this.addEventHandler(MouseEvent.MOUSE_PRESSED, e -> {
|
||||
width = this.getWidth();
|
||||
height = this.getHeight();
|
||||
|
||||
if (rectangleCtrl == RectangleCtrl.MOVE) {
|
||||
moveX = e.getScreenX() - this.getLayoutX();
|
||||
moveY = e.getScreenY() - this.getLayoutY();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 鼠标移动
|
||||
*/
|
||||
private void bindMouseMovedEvent() {
|
||||
this.addEventHandler(MouseEvent.MOUSE_MOVED, e -> {
|
||||
double width = this.getWidth(),
|
||||
height = this.getHeight(),
|
||||
x = e.getScreenX() - this.getLayoutX(),
|
||||
y = e.getScreenY() - this.getLayoutY();
|
||||
|
||||
|
||||
// topLeft
|
||||
if (x <= borderWidth && y <= borderWidth) {
|
||||
this.setCursor(Cursor.SE_RESIZE);
|
||||
rectangleCtrl = RectangleCtrl.TOP_LEFT;
|
||||
return;
|
||||
}
|
||||
|
||||
// topMiddle
|
||||
if (x <= width - borderWidth && y <= borderWidth) {
|
||||
this.setCursor(Cursor.N_RESIZE);
|
||||
rectangleCtrl = RectangleCtrl.TOP_MIDDLE;
|
||||
return;
|
||||
}
|
||||
|
||||
// topRight
|
||||
if (x <= width && y <= borderWidth) {
|
||||
this.setCursor(Cursor.NE_RESIZE);
|
||||
rectangleCtrl = RectangleCtrl.TOP_RIGHT;
|
||||
return;
|
||||
}
|
||||
|
||||
// centerLeft
|
||||
if (x <= borderWidth && y <= height - borderWidth) {
|
||||
this.setCursor(Cursor.W_RESIZE);
|
||||
rectangleCtrl = RectangleCtrl.CENTER_LEFT;
|
||||
return;
|
||||
}
|
||||
|
||||
// bottomLeft
|
||||
if (x <= borderWidth && y <= height) {
|
||||
this.setCursor(Cursor.NE_RESIZE);
|
||||
rectangleCtrl = RectangleCtrl.BOTTOM_LEFT;
|
||||
return;
|
||||
}
|
||||
|
||||
// bottomMiddle
|
||||
if (x <= width - borderWidth && y >= height - borderWidth) {
|
||||
this.setCursor(Cursor.N_RESIZE);
|
||||
rectangleCtrl = RectangleCtrl.BOTTOM_MIDDLE;
|
||||
return;
|
||||
}
|
||||
|
||||
// bottomRight
|
||||
if (x <= width && y >= height - borderWidth) {
|
||||
this.setCursor(Cursor.SE_RESIZE);
|
||||
rectangleCtrl = RectangleCtrl.BOTTOM_RIGHT;
|
||||
return;
|
||||
}
|
||||
|
||||
// centerRight
|
||||
if (x >= width - borderWidth && y <= height) {
|
||||
this.setCursor(Cursor.W_RESIZE);
|
||||
rectangleCtrl = RectangleCtrl.CENTER_RIGHT;
|
||||
return;
|
||||
}
|
||||
|
||||
// 移动指针
|
||||
if (x >= borderWidth + 1 && x <= width - borderWidth && y >= borderWidth + 1 && y <= height - borderWidth) {
|
||||
this.setCursor(Cursor.MOVE);
|
||||
rectangleCtrl = RectangleCtrl.MOVE;
|
||||
return;
|
||||
}
|
||||
|
||||
this.setCursor(Cursor.DEFAULT);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 鼠标拖拽
|
||||
*/
|
||||
private void bindMouseDraggedEvent() {
|
||||
this.addEventHandler(MouseEvent.MOUSE_DRAGGED, e -> {
|
||||
// 防止快速操作
|
||||
if (rectangleCtrl == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
double screenX = e.getScreenX(),
|
||||
screenY = e.getScreenY(),
|
||||
x = screenX - originX,
|
||||
y = screenY - originY;
|
||||
|
||||
|
||||
switch (rectangleCtrl) {
|
||||
case TOP_LEFT -> {
|
||||
this.setLayoutX(screenX);
|
||||
this.setLayoutY(screenY);
|
||||
this.setPrefSize(width - x, height - y);
|
||||
}
|
||||
|
||||
case TOP_MIDDLE -> {
|
||||
this.setLayoutY(screenY);
|
||||
this.setPrefHeight(height - y);
|
||||
}
|
||||
|
||||
case TOP_RIGHT -> {
|
||||
this.setLayoutY(screenY);
|
||||
this.setPrefSize(x, height - y);
|
||||
}
|
||||
|
||||
case CENTER_LEFT -> {
|
||||
this.setLayoutX(screenX);
|
||||
this.setPrefWidth(width - x);
|
||||
}
|
||||
|
||||
case CENTER_RIGHT -> this.setPrefWidth(x);
|
||||
|
||||
case BOTTOM_LEFT -> {
|
||||
this.setLayoutX(screenX);
|
||||
this.setPrefSize(width - x, y);
|
||||
}
|
||||
|
||||
case BOTTOM_MIDDLE -> this.setPrefHeight(y);
|
||||
|
||||
case BOTTOM_RIGHT -> {
|
||||
this.setPrefSize(x, y);
|
||||
}
|
||||
|
||||
case MOVE -> {
|
||||
this.setLayoutX(screenX - moveX);
|
||||
this.setLayoutY(screenY - moveY);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 鼠标抬起
|
||||
*/
|
||||
private void bindMouseReleasedEvent() {
|
||||
this.addEventHandler(MouseEvent.MOUSE_RELEASED, e -> {
|
||||
this.originX = this.getLayoutX();
|
||||
this.originY = this.getLayoutY();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 监听键盘按下
|
||||
*/
|
||||
private void bindKeyPressedEvent() {
|
||||
|
||||
}
|
||||
}
|
|
@ -3,19 +3,14 @@ package org.rococy.roomit.controller;
|
|||
import javafx.event.EventHandler;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.fxml.Initializable;
|
||||
import javafx.scene.Group;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.canvas.GraphicsContext;
|
||||
import javafx.scene.input.KeyEvent;
|
||||
import javafx.scene.input.MouseEvent;
|
||||
import javafx.scene.layout.Border;
|
||||
import javafx.scene.layout.Pane;
|
||||
import javafx.scene.paint.Paint;
|
||||
import javafx.scene.shape.Ellipse;
|
||||
import javafx.scene.shape.Shape;
|
||||
import javafx.scene.shape.StrokeLineCap;
|
||||
import javafx.scene.shape.StrokeLineJoin;
|
||||
import org.rococy.roomit.control.ResizableRectangle;
|
||||
import org.rococy.roomit.control.Toast;
|
||||
import org.rococy.roomit.domain.TransparentCanvas;
|
||||
import org.rococy.roomit.control.*;
|
||||
import org.rococy.roomit.symbol.BrushSymbol;
|
||||
import org.rococy.roomit.symbol.CircleSymbol;
|
||||
import org.rococy.roomit.symbol.RectangleSymbol;
|
||||
|
@ -36,15 +31,10 @@ public class WindowController implements Initializable {
|
|||
@FXML
|
||||
private Pane pane;
|
||||
|
||||
private List<Node> paneChildren;
|
||||
|
||||
private final Group canvasGroup = new Group();
|
||||
|
||||
/**
|
||||
* canvas配置
|
||||
* 最外层pane的子元素集合
|
||||
*/
|
||||
private static final int TRANSPARENT_CANVAS_COUNT = 5;
|
||||
private static boolean isTransparent = true;
|
||||
private List<Node> paneChildren;
|
||||
|
||||
/**
|
||||
* 画笔
|
||||
|
@ -66,93 +56,151 @@ public class WindowController implements Initializable {
|
|||
*/
|
||||
private static Shape mouseLogo = BRUSH_SYMBOL;
|
||||
|
||||
/**
|
||||
* 画笔
|
||||
*/
|
||||
private GraphicsContext gc;
|
||||
|
||||
/**
|
||||
* 全局x,y轴
|
||||
* 画板x,y轴
|
||||
* 画矩形、圆形的x,y轴
|
||||
*/
|
||||
private double globalMouseX, globalMouseY, graphicStartX, graphicStartY, shapeStartX, shapeStartY;
|
||||
private double globalMouseX, globalMouseY, shapeStartX, shapeStartY;
|
||||
|
||||
/**
|
||||
* 状态:1 画笔,2 矩形,3圆形
|
||||
*/
|
||||
private static int paintState = SymbolConsts.BRUSH;
|
||||
|
||||
/**
|
||||
* 置顶、置底
|
||||
*/
|
||||
private static final int TO_FRONT = 0;
|
||||
private static final int TO_BACK = 100;
|
||||
|
||||
ResizableRectangle rectangle;
|
||||
Pane rectanglePane;
|
||||
|
||||
ResizableEllipseWrapper resizableEllipseWrapper;
|
||||
Ellipse ellipse;
|
||||
|
||||
private final CanvasGroup canvasGroup = new CanvasGroup();
|
||||
private final ShapePane shapePane = new ShapePane();
|
||||
|
||||
@FXML
|
||||
public void keyPressed(KeyEvent event) {
|
||||
if (event.isControlDown()) {
|
||||
switch (event.getCode()) {
|
||||
case G -> paintState = SymbolConsts.BRUSH;
|
||||
case G -> {
|
||||
paintState = SymbolConsts.BRUSH;
|
||||
switchPane();
|
||||
}
|
||||
case R -> {
|
||||
paintState = SymbolConsts.RECTANGLE;
|
||||
switchPane();
|
||||
|
||||
if (rectangle == null) {
|
||||
rectanglePane = new Pane();
|
||||
rectanglePane.setPrefSize(ScreenUtils.getScreenWidth(), ScreenUtils.getScreenHeight());
|
||||
rectanglePane.setViewOrder(0);
|
||||
shapePane.setOnMousePressed(e -> {
|
||||
if (paintState == SymbolConsts.BRUSH || e.getTarget() != shapePane) {
|
||||
return;
|
||||
}
|
||||
|
||||
rectanglePane.setOnMousePressed(e -> {
|
||||
if (paintState == SymbolConsts.BRUSH || e.getTarget() != rectanglePane) {
|
||||
return;
|
||||
}
|
||||
shapeStartX = e.getX();
|
||||
shapeStartY = e.getY();
|
||||
|
||||
rectangle = new ResizableRectangle(shapeStartX, shapeStartY);
|
||||
shapePane.addChildren(rectangle);
|
||||
|
||||
shapeStartX = e.getX();
|
||||
shapeStartY = e.getY();
|
||||
rectangle.setLayoutX(shapeStartX);
|
||||
rectangle.setLayoutY(shapeStartY);
|
||||
});
|
||||
|
||||
rectangle = new ResizableRectangle(shapeStartX, shapeStartY);
|
||||
rectanglePane.getChildren().add(rectangle);
|
||||
shapePane.setOnMouseDragged(e -> {
|
||||
if (paintState == SymbolConsts.BRUSH || e.getTarget() != shapePane) {
|
||||
return;
|
||||
}
|
||||
|
||||
double endX = e.getX();
|
||||
double endY = e.getY();
|
||||
|
||||
// 向左上角方向拉伸检测
|
||||
if (endX < shapeStartX && endY < shapeStartY) {
|
||||
rectangle.setLayoutX(endX);
|
||||
rectangle.setLayoutY(endY);
|
||||
rectangle.setPrefSize(shapeStartX - endX, shapeStartY - endY);
|
||||
} else if (endX < shapeStartX) {
|
||||
// 直直往左拉伸检测
|
||||
rectangle.setLayoutX(endX);
|
||||
rectangle.setPrefSize(shapeStartX - endX, endY - shapeStartY);
|
||||
} else if (endY < shapeStartY) {
|
||||
// 直直往上拉伸检测
|
||||
rectangle.setLayoutY(endY);
|
||||
rectangle.setPrefSize(endX - shapeStartX, shapeStartY - endY);
|
||||
} else {
|
||||
// 正常拉伸矩形
|
||||
rectangle.setPrefSize(endX - shapeStartX, endY - shapeStartY);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
case Q -> {
|
||||
paintState = SymbolConsts.CIRCLE;
|
||||
switchPane();
|
||||
|
||||
shapePane.setOnMousePressed(e -> {
|
||||
if (paintState == SymbolConsts.BRUSH || e.getTarget() != shapePane) {
|
||||
return;
|
||||
}
|
||||
shapeStartX = e.getSceneX();
|
||||
shapeStartY = e.getSceneY();
|
||||
|
||||
resizableEllipseWrapper = new ResizableEllipseWrapper(shapeStartX, shapeStartY);
|
||||
|
||||
ellipse = resizableEllipseWrapper.getInnerEllipse();
|
||||
|
||||
resizableEllipseWrapper.setLayoutX(shapeStartX);
|
||||
resizableEllipseWrapper.setLayoutY(shapeStartY);
|
||||
|
||||
shapePane.addChildren(resizableEllipseWrapper);
|
||||
});
|
||||
|
||||
shapePane.setOnMouseDragged(e -> {
|
||||
if (paintState == SymbolConsts.BRUSH || e.getTarget() != shapePane) {
|
||||
return;
|
||||
}
|
||||
double endX = e.getSceneX();
|
||||
double endY = e.getSceneY();
|
||||
|
||||
// 向左上角方向拉伸检测
|
||||
if (endX < shapeStartX && endY < shapeStartY) {
|
||||
resizableEllipseWrapper.setLayoutX(endX);
|
||||
resizableEllipseWrapper.setLayoutY(endY);
|
||||
resizableEllipseWrapper.setPrefSize(shapeStartX - endX, shapeStartY - endY);
|
||||
} else if (endX < shapeStartX) {
|
||||
// 直直往左拉伸检测
|
||||
resizableEllipseWrapper.setLayoutX(endX);
|
||||
resizableEllipseWrapper.setPrefSize(shapeStartX - endX, endY - shapeStartY);
|
||||
} else if (endY < shapeStartY) {
|
||||
// 直直往上拉伸检测
|
||||
resizableEllipseWrapper.setLayoutY(endY);
|
||||
resizableEllipseWrapper.setPrefSize(endX - shapeStartX, shapeStartY - endY);
|
||||
} else {
|
||||
// 正常拉伸矩形
|
||||
resizableEllipseWrapper.setPrefSize(endX - shapeStartX, endY - shapeStartY);
|
||||
}
|
||||
|
||||
double centerX = resizableEllipseWrapper.getPrefWidth() / 2;
|
||||
double centerY = resizableEllipseWrapper.getPrefHeight() / 2;
|
||||
|
||||
ellipse.setCenterX(centerX);
|
||||
ellipse.setCenterY(centerY);
|
||||
|
||||
ellipse.setRadiusX(centerX - resizableEllipseWrapper.getEllipseIntervals());
|
||||
ellipse.setRadiusY(centerY - resizableEllipseWrapper.getEllipseIntervals());
|
||||
});
|
||||
|
||||
shapePane.setOnMouseReleased(e -> {
|
||||
if (e.getScreenX() >= resizableEllipseWrapper.getLayoutX() + resizableEllipseWrapper.getPrefWidth()
|
||||
&& e.getScreenY() >= resizableEllipseWrapper.getLayoutY() + resizableEllipseWrapper.getPrefHeight()) {
|
||||
resizableEllipseWrapper.setBorder(Border.EMPTY);
|
||||
}
|
||||
});
|
||||
|
||||
rectangle.setLayoutX(shapeStartX);
|
||||
rectangle.setLayoutY(shapeStartY);
|
||||
});
|
||||
|
||||
rectanglePane.setOnMouseDragged(e -> {
|
||||
if (paintState == SymbolConsts.BRUSH || e.getTarget() != rectanglePane) {
|
||||
return;
|
||||
}
|
||||
|
||||
double endX = e.getX();
|
||||
double endY = e.getY();
|
||||
|
||||
// 向左上角方向拉伸检测
|
||||
if (endX < shapeStartX && endY < shapeStartY) {
|
||||
rectangle.setLayoutX(endX);
|
||||
rectangle.setLayoutY(endY);
|
||||
|
||||
rectangle.setWidth(shapeStartX - endX);
|
||||
rectangle.setHeight(shapeStartY - endY);
|
||||
} else if (endX < shapeStartX) {
|
||||
// 直直往左拉伸检测
|
||||
rectangle.setLayoutX(endX);
|
||||
rectangle.setWidth(shapeStartX - endX);
|
||||
rectangle.setHeight(endY - shapeStartY);
|
||||
} else if (endY < shapeStartY) {
|
||||
// 直直往上拉伸检测
|
||||
rectangle.setLayoutY(endY);
|
||||
rectangle.setWidth(endX - shapeStartX);
|
||||
rectangle.setHeight(shapeStartY - endY);
|
||||
} else {
|
||||
// 正常拉伸矩形
|
||||
rectangle.setWidth(endX - shapeStartX);
|
||||
rectangle.setHeight(endY - shapeStartY);
|
||||
}
|
||||
});
|
||||
|
||||
paneChildren.add(rectanglePane);
|
||||
}
|
||||
}
|
||||
case Q -> paintState = SymbolConsts.CIRCLE;
|
||||
}
|
||||
|
||||
changeMouseLogo();
|
||||
|
@ -172,7 +220,6 @@ public class WindowController implements Initializable {
|
|||
changeMouseLogo();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 初始化控件
|
||||
*
|
||||
|
@ -181,11 +228,11 @@ public class WindowController implements Initializable {
|
|||
*/
|
||||
@Override
|
||||
public void initialize(URL location, ResourceBundle resources) {
|
||||
initPane();
|
||||
initCanvasSheet();
|
||||
initPaneWrapper();
|
||||
initDrawingBoard();
|
||||
}
|
||||
|
||||
private void initPane() {
|
||||
private void initPaneWrapper() {
|
||||
pane.setPrefSize(ScreenUtils.getScreenWidth(), ScreenUtils.getScreenWidth());
|
||||
paneChildren = pane.getChildren();
|
||||
paneChildren.add(new Toast("屏幕工具已开启", 500));
|
||||
|
@ -206,85 +253,25 @@ public class WindowController implements Initializable {
|
|||
pane.setOnMouseMoved(paneMouseEventHandler);
|
||||
}
|
||||
|
||||
private void initCanvasSheet() {
|
||||
if (isTransparent) {
|
||||
// 初始化层叠Canvas
|
||||
for (int i = 0; i < TRANSPARENT_CANVAS_COUNT; i++) {
|
||||
TransparentCanvas canvas = new TransparentCanvas();
|
||||
canvas.setViewOrder(i);
|
||||
bindCanvasEvents(canvas);
|
||||
bindCanvasTransparentEvents(canvas);
|
||||
canvasGroup.getChildren().add(canvas);
|
||||
}
|
||||
} else {
|
||||
// 直接给一个Canvas即可
|
||||
TransparentCanvas canvas = new TransparentCanvas();
|
||||
bindCanvasEvents(canvas);
|
||||
canvasGroup.getChildren().add(canvas);
|
||||
}
|
||||
canvasGroup.setViewOrder(100);
|
||||
private void initDrawingBoard() {
|
||||
paneChildren.add(canvasGroup);
|
||||
paneChildren.add(shapePane);
|
||||
|
||||
canvasGroup.setViewOrder(TO_FRONT);
|
||||
shapePane.setViewOrder(TO_BACK);
|
||||
}
|
||||
|
||||
private void bindCanvasTransparentEvents(TransparentCanvas canvas) {
|
||||
// 鼠标抬起,开始透明操作
|
||||
canvas.setOnMouseReleased(e -> {
|
||||
// 当前画完的Canvas开始变透明
|
||||
canvas.startTransparency();
|
||||
|
||||
List<Node> nodeList = canvasGroup.getChildren();
|
||||
|
||||
for (Node node : nodeList) {
|
||||
if (!(node instanceof TransparentCanvas)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 即将置于顶层的canvas
|
||||
TransparentCanvas topCanvas = (TransparentCanvas) node;
|
||||
|
||||
// 正在隐藏当中
|
||||
if (!topCanvas.isUsed() || topCanvas == canvas) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 交换图形层叠位置
|
||||
canvas.setViewOrder(topCanvas.getViewOrder());
|
||||
topCanvas.setViewOrder(0);
|
||||
break;
|
||||
private void switchPane() {
|
||||
switch (paintState) {
|
||||
case SymbolConsts.RECTANGLE, SymbolConsts.CIRCLE -> {
|
||||
shapePane.setViewOrder(TO_FRONT);
|
||||
canvasGroup.setViewOrder(TO_BACK);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void bindCanvasEvents(TransparentCanvas canvas) {
|
||||
// 鼠标按下
|
||||
canvas.setOnMousePressed(e -> {
|
||||
graphicStartX = e.getX();
|
||||
graphicStartY = e.getY();
|
||||
|
||||
gc = canvas.getGraphicsContext2D();
|
||||
});
|
||||
|
||||
// 鼠标按下并拖动
|
||||
canvas.setOnMouseDragged(e -> {
|
||||
double endX = e.getX();
|
||||
double endY = e.getY();
|
||||
|
||||
gc.setStroke(Paint.valueOf("#f00"));
|
||||
|
||||
// 让线变得圆滑
|
||||
gc.setLineCap(StrokeLineCap.ROUND);
|
||||
gc.setLineJoin(StrokeLineJoin.ROUND);
|
||||
// 线条宽度
|
||||
gc.setLineWidth(5);
|
||||
|
||||
// 画线
|
||||
gc.strokeLine(graphicStartX, graphicStartY, endX, endY);
|
||||
|
||||
// 连续画线
|
||||
graphicStartX = endX;
|
||||
graphicStartY = endY;
|
||||
});
|
||||
case SymbolConsts.BRUSH -> {
|
||||
shapePane.setViewOrder(TO_BACK);
|
||||
canvasGroup.setViewOrder(TO_FRONT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void changeMouseLogo() {
|
||||
|
|
|
@ -1,52 +0,0 @@
|
|||
package org.rococy.roomit.domain;
|
||||
|
||||
import javafx.scene.canvas.Canvas;
|
||||
import org.rococy.roomit.util.ScreenUtils;
|
||||
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
/**
|
||||
* 自动透明的Canvas
|
||||
*
|
||||
* @author Rococy
|
||||
* @date 2022/9/13
|
||||
*/
|
||||
public class TransparentCanvas extends Canvas {
|
||||
|
||||
private double opacity = 1;
|
||||
|
||||
private boolean used = true;
|
||||
|
||||
public TransparentCanvas() {
|
||||
super(ScreenUtils.getScreenWidth(), ScreenUtils.getScreenHeight());
|
||||
}
|
||||
|
||||
public void startTransparency() {
|
||||
used = false;
|
||||
new Timer().schedule(new OpacityTask(), 0, 100);
|
||||
}
|
||||
|
||||
public boolean isUsed() {
|
||||
return used;
|
||||
}
|
||||
|
||||
private class OpacityTask extends TimerTask {
|
||||
|
||||
private final TransparentCanvas canvas = TransparentCanvas.this;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
opacity *= 0.9;
|
||||
canvas.setOpacity(opacity);
|
||||
|
||||
if (opacity < 0.1) {
|
||||
used = true;
|
||||
opacity = 1;
|
||||
canvas.getGraphicsContext2D().clearRect(0,0, canvas.getWidth(), canvas.getHeight());
|
||||
canvas.setOpacity(opacity);
|
||||
this.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,6 +8,10 @@ import javafx.scene.shape.Circle;
|
|||
*/
|
||||
public abstract class BaseCircleSymbol extends Circle implements MouseSymbol {
|
||||
|
||||
public BaseCircleSymbol() {
|
||||
this.setViewOrder(1000);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseCircleSymbol position(double x, double y) {
|
||||
this.setCenterX(x);
|
||||
|
|
|
@ -8,6 +8,10 @@ import javafx.scene.shape.Rectangle;
|
|||
*/
|
||||
public abstract class BaseRectangleSymbol extends Rectangle implements MouseSymbol {
|
||||
|
||||
public BaseRectangleSymbol() {
|
||||
this.setViewOrder(1000);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseRectangleSymbol position(double x, double y) {
|
||||
this.setX(x);
|
||||
|
|
Loading…
Reference in New Issue