JAVAFx自定义拖拽放大与缩小

场景描述

javaFx stage设置成没有窗口装饰的样式时,相应的拖拽放大与缩小功能也会消失,参照资料手动添加了对应功能。

存在问题

找了许多网上的实现方法几乎都是只实现右侧、下端和右下端边界的放大缩小功能。补充完其他边界的功能后发现另外几边拖拉会出现闪屏问题(强迫症表示不能忍受)。暂时没有想到修复的方法

代码

定义鼠标到达边界的样式以及在相应区域内触发拖拉产生的事件

/**
 * 说明:拖拽放大与缩小事件监听
 *
 * @author Li BangFa
 * @date 2022-07-19 16:17
 */
public class FlexibleListener implements EventHandler<MouseEvent> {


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

    /**
     * 是否处于调整窗口状态
     */
    private static boolean within;


    private final Stage stage;
    private Node node = null;

    public FlexibleListener(Stage stage) {
        this.stage = stage;
    }

    @Override
    public void handle(MouseEvent event) {
        if (event.getEventType() == MouseEvent.MOUSE_MOVED) {
            //事件被消费,不在执行其他任务
            event.consume();
            double x = event.getSceneX();
            double y = event.getSceneY();
            double width = stage.getWidth();
            double height = stage.getHeight();

            // 鼠标光标初始为默认类型,若未进入调整窗口状态,保持默认类型
            Cursor cursorType = position(x, y, width, height);

            node.setCursor(cursorType);
        }

        if (event.getEventType() == MouseEvent.MOUSE_DRAGGED && within) {
            double x = event.getSceneX();
            double y = event.getSceneY();
            // 保存窗口改变后的x、y坐标和宽度、高度,用于预判是否会小于最小宽度、最小高度
            double nextX = stage.getX();
            double nextY = stage.getY();
            double nextWidth = stage.getWidth();
            double nextHeight = stage.getHeight();

            //鼠标焦点位于左侧边界,执行左右移动
            if (Cursor.NW_RESIZE.equals(node.getCursor())
                    || Cursor.W_RESIZE.equals(node.getCursor())
                    || Cursor.SW_RESIZE.equals(node.getCursor())) {
                double width = Math.max(nextWidth - x, MIN_WIDTH);
                nextX = nextX + nextWidth - width;
                nextWidth = width;
            }

            //鼠标焦点位于右侧边界,执行左右移动
            if (Cursor.NE_RESIZE.equals(node.getCursor())
                    || Cursor.E_RESIZE.equals(node.getCursor())
                    || Cursor.SE_RESIZE.equals(node.getCursor())) {
                nextWidth = Math.max(x, MIN_WIDTH);
            }

            //鼠标焦点位于顶部边界,执行上下移动
            if (Cursor.SW_RESIZE.equals(node.getCursor())
                    || Cursor.SE_RESIZE.equals(node.getCursor())
                    || Cursor.S_RESIZE.equals(node.getCursor())) {
                nextHeight = Math.max(y, MIN_HEIGHT);
            }

            //鼠标焦点位于底部边界,执行上下移动
            if (Cursor.NW_RESIZE.equals(node.getCursor())
                    || Cursor.N_RESIZE.equals(node.getCursor())
                    || Cursor.NE_RESIZE.equals(node.getCursor())) {
                double height = Math.max(nextHeight - y, MIN_HEIGHT);
                nextY = nextY + nextHeight - height;
                nextHeight = height;
            }

            // 最后统一改变窗口的x、y坐标和宽度、高度,可以防止刷新频繁出现的屏闪情况
            stage.setX(nextX);
            stage.setY(nextY);
            stage.setWidth(nextWidth);
            stage.setHeight(nextHeight);
        }
    }

    public void enableDrag(Node node) {
        this.node = node;
        node.setOnMouseMoved(this);
        node.setOnMouseDragged(this);
    }

    /**
     * 判断当前鼠标所在的位置并根据位置显示对应的形状
     * 以及是否触发对应的伸缩事件
     *
     * @param x      鼠标坐标x
     * @param y      鼠标坐标y
     * @param width  stage窗口的宽度
     * @param height stage窗口的高度
     * @return 鼠标显示类型
     */
    private static Cursor position(double x, double y, double width, double height) {
        within = true;

        //左上判断
        if (x < RESIZE_WIDTH && x >= 0 && y >= 0 && y < RESIZE_WIDTH) {
            return Cursor.NW_RESIZE;
        }

        //左侧判断
        if (x < RESIZE_WIDTH && x >= 0 && y >= RESIZE_WIDTH && y < height - RESIZE_WIDTH) {
            return Cursor.W_RESIZE;
        }

        //左下判断
        if (x < RESIZE_WIDTH && x >= 0 && y >= height - RESIZE_WIDTH && y < height) {
            return Cursor.SW_RESIZE;
        }

        //上侧判断
        if (x < width - RESIZE_WIDTH && x >= RESIZE_WIDTH && y >= 0 && y < RESIZE_WIDTH) {
            return Cursor.N_RESIZE;
        }

        //上右判断
        if (x < width && x >= width - RESIZE_WIDTH && y >= 0 && y < RESIZE_WIDTH) {
            return Cursor.NE_RESIZE;
        }

        //右侧判断
        if (x < width && x >= width - RESIZE_WIDTH && y >= RESIZE_WIDTH && y < height - RESIZE_WIDTH) {
            return Cursor.E_RESIZE;
        }

        //右下判断
        if (x < width && x >= width - RESIZE_WIDTH && y >= height - RESIZE_WIDTH && y < height) {
            return Cursor.SE_RESIZE;
        }

        //下方判断
        if (x < width - RESIZE_WIDTH && x >= RESIZE_WIDTH && y >= height - RESIZE_WIDTH && y < height) {
            return Cursor.S_RESIZE;
        }

        within = false;
        return Cursor.DEFAULT;
    }
}

Controller方法初始化的时候直接把该监听添加到根布局上面

@FXMLController
@Slf4j
public class MainFrameController implements Initializable {
    @FXML
    private AnchorPane rootPane;
    @FXML
    private HBox titleBox;

    @Resource
    private FxBasicsService fxBasicsService;

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        //获取到stage对象
        Stage primaryStage = AbstractJavaFxApplicationSupport.getStage();

        //页面的根布局样式
        rootPane.setPrefSize(primaryStage.getWidth(), primaryStage.getHeight());
        new FlexibleListener(primaryStage).enableDrag(rootPane);

        //标题行
        titleBox.setPrefSize(primaryStage.getWidth(), 30.0);
    }
}

参考文件
https://www.shuzhiduo.com/A/gAJGeZGndZ/

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值