JavaFX 自定义窗口拉伸与移动 (向左向上拉伸,无闪烁)

不想多说直接上代码,有注释应该可以看懂

public class DrawUtil {
    //窗体拉伸属性
    private  boolean isRight;// 是否处于右边界调整窗口状态
    private  boolean isLeft;// 是否处于左边界调整窗口状态
    private  boolean isTop;// 是否处于上边界调整窗口状态
    private  boolean isBottom;// 是否处于下边界调整窗口状态
    private  boolean isTopLeft;// 是否处于左上角调整窗口状态
    private  boolean isTopRight;// 是否处于右上角调整窗口状态
    private  boolean isBottomRight;// 是否处于右下角调整窗口状态
    private  boolean isBottomLeft;// 是否处于左下角调整窗口状态

    private Cursor cursorType;// 鼠标光标类型

    private double nextWidth;
    private double nextHeight;

    private  double xOffSet;
    private  double yOffSet;

    private  long lastUpdateTime;


    private final static int RESIZE_WIDTH = 5;// 判定是否为调整窗口状态的范围与边界距离
    private final double MIN_WIDTH ;// 窗口最小宽度
    private final double MIN_HEIGHT;// 窗口最小高度

    public DrawUtil(double minWidth, double minHeight) {
        MIN_WIDTH = minWidth;
        MIN_HEIGHT = minHeight;
    }

    public DrawUtil() {
        MIN_WIDTH = 0;
        MIN_HEIGHT = 0;
    }

    /**
     * 添加拉伸窗口功能
     * @param stage
     * @param root
     */
    public void addStretch(Stage stage, Node root) {


        // 添加鼠标移动事件,检测鼠标位置,修改鼠标样式
        root.setOnMouseMoved((MouseEvent event) -> {
            event.consume();
            // 重置所有调整窗口状态
            isRight = isBottomRight = isBottom = isLeft = isTop = isTopRight =  isTopLeft = isBottomLeft = false;

            double sceneX = event.getSceneX();//获取场景X
            double sceneY = event.getSceneY();//获取场景Y
            double width = stage.getWidth();
            double height = stage.getHeight();



            // 检查顶部区域
            if (sceneY < RESIZE_WIDTH) {
                if (sceneX < RESIZE_WIDTH ) {// 左上角
                    isTopLeft = true;
                    cursorType = Cursor.NW_RESIZE;
                } else if (sceneX > width - RESIZE_WIDTH) {// 右上角
                    isTopRight = true;
                    cursorType = Cursor.NE_RESIZE;
                } else {//顶部
                    isTop = true;
                    cursorType = Cursor.N_RESIZE;
                }
            }
            // 检查底部区域
            else if (sceneY > height - RESIZE_WIDTH) {
                if (sceneX < RESIZE_WIDTH) {// 左下角
                    isBottomLeft = true;
                    cursorType = Cursor.SW_RESIZE;
                } else if (sceneX > width - RESIZE_WIDTH) {// 右下角
                    isBottomRight = true;
                    cursorType = Cursor.SE_RESIZE;
                } else {
                    isBottom = true;
                    cursorType = Cursor.S_RESIZE;
                }
            }

                // 检查左右边界
            if (sceneX < RESIZE_WIDTH && sceneX > - RESIZE_WIDTH) {
                isLeft = true;
                cursorType = Cursor.W_RESIZE;
            }
             else if (sceneX > width - RESIZE_WIDTH && sceneX < width + RESIZE_WIDTH) {
                isRight = true;
                cursorType = Cursor.E_RESIZE;
            }

            // 默认情况
            else if (sceneX > RESIZE_WIDTH && sceneX < width - RESIZE_WIDTH && sceneY > RESIZE_WIDTH && sceneY < height - RESIZE_WIDTH) {
                cursorType = Cursor.DEFAULT;
            }
            // 最后改变鼠标光标
            root.setCursor(cursorType);
        });

        // 添加鼠标按下事件
        root.setOnMousePressed((MouseEvent event) -> {

            xOffSet = event.getX();
            yOffSet = event.getY();
            nextWidth = stage.getWidth();
            nextHeight = stage.getHeight();
        });

        // 添加鼠标拖拽事件,动态增大窗口
        root.setOnMouseDragged((MouseEvent event) -> {

            if (isTop || isTopLeft || isTopRight || isBottom || isBottomLeft || isBottomRight || isLeft || isRight) {

                double mouseX = event.getX();
                double mouseY = event.getY();
                // 保存窗口改变后的x、y坐标和宽度、高度,用于预判是否会小于最小宽度、最小高度
                double nextX = stage.getX();
                double nextY = stage.getY();

                if (System.currentTimeMillis() - lastUpdateTime > 10) {

                if (isTop || isTopLeft || isTopRight) {// 所有上边调整窗口状态
                    nextY = nextY + (mouseY - yOffSet);
                    nextHeight = nextHeight - (mouseY - yOffSet);

                }
                if (isLeft || isTopLeft || isBottomLeft) {// 所有左边调整窗口状态
                    nextX = nextX + (mouseX - xOffSet);
                    nextWidth = nextWidth - (mouseX - xOffSet);

                }

                if (isRight || isTopRight || isBottomRight) {// 所有右边调整窗口状态
                    nextWidth = mouseX;

                }
                if (isBottom || isBottomLeft || isBottomRight) {// 所有下边调整窗口状态
                    nextHeight = mouseY;

                }

                if (MIN_WIDTH != 0 && MIN_HEIGHT != 0) {
                    if (nextWidth <= MIN_WIDTH) {// 如果窗口改变后的宽度小于最小宽度,则宽度调整到最小宽度
                        nextWidth = MIN_WIDTH;
                    }
                    if (nextHeight <= MIN_HEIGHT) {// 如果窗口改变后的高度小于最小高度,则高度调整到最小高度
                        nextHeight = MIN_HEIGHT;
                    }
                }


                // 使用缓冲区或延迟更新逻辑,避免频繁更新
                    stage.setX(nextX);
                    stage.setY(nextY);
                    stage.setWidth(nextWidth);
                    stage.setHeight(nextHeight);
//                    stage.sizeToScene();
                    lastUpdateTime = System.currentTimeMillis();
                }

            }

        });
    }

    /**
     * 添加移动窗口功能
     * 鼠标拖动指定组件才可以移动窗口
     * @param stage
     * @param targetPane
     */
    public void addMoveWindow(Stage stage, Pane targetPane) {
        targetPane.addEventFilter(MouseEvent.MOUSE_DRAGGED, event -> {
            stage.setX(event.getScreenX() - xOffSet);
            stage.setY(event.getScreenY() - yOffSet);
        });
    }

    /**
     * 添加移动窗口功能
     * 鼠标拖动窗口所有地方都可以移动
     * @param stage
     */
    public void addMoveWindow(Stage stage) {
        stage.addEventFilter(MouseEvent.MOUSE_DRAGGED, event -> {
            stage.setX(event.getScreenX() - xOffSet);
            stage.setY(event.getScreenY() - yOffSet);
        });
    }
}

直接将这个类注入到Application中,并调用对应的方法就可以了

  • 7
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
JavaFX提供了一种简单的方法来自定义窗口样式,可以使用CSS样式表来改变窗口的外观。以下是步骤: 1. 创建一个新的CSS文件,例如“custom.css”。 2. 在CSS文件中定义你想要的样式,例如: ```css .root { -fx-background-color: #333; } .title-bar { -fx-background-color: #444; -fx-text-fill: white; } .close-button { -fx-background-color: #f00; -fx-text-fill: white; } ``` 3. 在JavaFX应用程序的启动方法中加载CSS文件,并将样式应用到窗口。 ```java public class Main extends Application { @Override public void start(Stage primaryStage) throws Exception{ Parent root = FXMLLoader.load(getClass().getResource("sample.fxml")); primaryStage.setTitle("Custom Window Style"); // Load custom CSS style Scene scene = new Scene(root); scene.getStylesheets().add(getClass().getResource("custom.css").toExternalForm()); // Apply custom style to window primaryStage.initStyle(StageStyle.UNDECORATED); primaryStage.setScene(scene); primaryStage.show(); } public static void main(String[] args) { launch(args); } } ``` 4. 在FXML文件中添加一个带有“title-bar”类的Pane,以模拟窗口标题栏。 ```xml <Pane id="title-bar" styleClass="title-bar" onMousePressed="#handleMousePressed" onMouseDragged="#handleMouseDragged"> <Label text="Custom Window Style" /> <Button id="close-button" styleClass="close-button" text="X" onMouseClicked="#handleCloseClicked" /> </Pane> ``` 5. 在控制器类中添加处理鼠标事件的方法,使窗口可以拖动和关闭。 ```java public class Controller { @FXML private void handleMousePressed(MouseEvent event) { xOffset = event.getSceneX(); yOffset = event.getSceneY(); } @FXML private void handleMouseDragged(MouseEvent event) { Stage stage = (Stage) ((Node) event.getSource()).getScene().getWindow(); stage.setX(event.getScreenX() - xOffset); stage.setY(event.getScreenY() - yOffset); } @FXML private void handleCloseClicked(MouseEvent event) { Stage stage = (Stage) ((Node) event.getSource()).getScene().getWindow(); stage.close(); } } ``` 这样,你就可以使用CSS样式表来创建自定义窗口样式了。注意,需要自己添加拖动和关闭窗口的代码逻辑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值