【问题标题】:resizing a substraction shape调整减法形状的大小
【发布时间】:2014-12-02 23:06:53
【问题描述】:

我想调整下面创建的形状。但无法得到它。 该项目是创建一个透明矩形以仅显示桌面的一部分,并隐藏其余部分。透明区域是减法的结果,我需要让用户调整它的大小。

我尝试了几种方法,例如从这里适应:https://gist.github.com/jewelsea/1441960

但无法得到它。

这是我的代码:

@Override
public void start(Stage stage) {
    Group group = new Group();
    Rectangle rect = new Rectangle(0, 0, 350, 300);
    Rectangle clip = new Rectangle(20, 20, 200, 200);
    clip.setArcHeight(15);
    clip.setArcWidth(15);

    Shape shape = Shape.subtract(rect, clip);

    shape.setFill(Color.GRAY);
    group.getChildren().add(shape);
    Scene scene = new Scene(group);
    scene.setFill(Color.TRANSPARENT);
    stage.initStyle(StageStyle.TRANSPARENT);
    stage.setScene(scene);
    stage.show();
}

任何链接或帮助将不胜感激。

【问题讨论】:

    标签: java javafx shapes


    【解决方案1】:

    如果您通过Shape.subtract(...) 创建了Shape,那么您之后就没有任何机制来更改它的属性(在更改用于创建它的形状的边界的意义上)。您必须从其父对象中删除形状,重新计算矩形和剪辑,重新计算形状,然后将新形状添加回场景中。

    在此处使用Path 可能会更好,这样您就可以操纵坐标而无需每次都创建新形状。绕外部(填充部分)以一种方式(例如顺时针)遍历,然后围绕内部(透明部分)以另一种方式(逆时针)遍历。所得形状将与从外部减去内部相同。初始设置可能需要更多代码,但您可以根据需要操作坐标。

    我不确定您正在寻找什么功能,但以下允许您通过单击并拖动来拖动内部部分,并允许您通过单击并拖动外部部分来移动整个窗口.这应该足以让您弄清楚您需要什么。我没有在示例中包含漂亮的圆角,但您可以使用 ArcTo 路径元素相当轻松地实现这些圆角。

    import javafx.application.Application;
    import javafx.application.Platform;
    import javafx.beans.binding.DoubleBinding;
    import javafx.beans.property.DoubleProperty;
    import javafx.beans.property.SimpleDoubleProperty;
    import javafx.beans.value.ObservableDoubleValue;
    import javafx.geometry.Point2D;
    import javafx.scene.Scene;
    import javafx.scene.layout.Pane;
    import javafx.scene.paint.Color;
    import javafx.scene.shape.ClosePath;
    import javafx.scene.shape.LineTo;
    import javafx.scene.shape.MoveTo;
    import javafx.scene.shape.Path;
    import javafx.scene.shape.PathElement;
    import javafx.stage.Stage;
    import javafx.stage.StageStyle;
    
    public class TransparentRectangle extends Application {
    
    
        @Override
        public void start(Stage stage) {
    
            Pane root = new Pane();
    
            PathElement start = new MoveTo(0, 0);
            PathElement outerTopRight = createBoundLineTo(root.widthProperty(), 0);
            PathElement outerBottomRight = createBoundLineTo(root.widthProperty(), root.heightProperty());
            PathElement outerBottomLeft = createBoundLineTo(0, root.heightProperty());
            PathElement outerTopLeft = new LineTo(0, 0);
    
            DoubleProperty innerLeft = new SimpleDoubleProperty(20);
            DoubleProperty innerTop = new SimpleDoubleProperty(20);
            DoubleBinding innerRight = innerLeft.add(180);
            DoubleBinding innerBottom = innerTop.add(180);
    
            PathElement innerTopLeft = createBoundLineTo(innerLeft, innerTop);
            PathElement innerTopRight = createBoundLineTo(innerRight, innerTop);
            PathElement innerBottomRight = createBoundLineTo(innerRight, innerBottom);
            PathElement innerBottomLeft = createBoundLineTo(innerLeft, innerBottom);
    
            Path path = new Path(
                    start, outerTopRight,
                    outerBottomRight, outerBottomLeft,
                    outerTopLeft, 
                    innerTopLeft, innerBottomLeft, 
                    innerBottomRight, innerTopRight,
                    innerTopLeft, new ClosePath()
            );
    
    
            path.setFill(Color.GRAY);
            path.setStroke(Color.TRANSPARENT);
            root.getChildren().add(path);
    
            class Wrapper<T> { T value ; }
            Wrapper<Point2D> mouseLocation = new Wrapper<>();
    
            // Drag on gray portion of path - move entire window:
            path.setOnDragDetected(event -> {
                mouseLocation.value = new Point2D(event.getScreenX(), event.getScreenY());
            });
            path.setOnMouseDragged(event -> {
                if (mouseLocation.value != null) {
                    stage.setX(stage.getX() + event.getScreenX() - mouseLocation.value.getX());
                    stage.setY(stage.getY() + event.getScreenY() - mouseLocation.value.getY());
                    mouseLocation.value = new Point2D(event.getScreenX(), event.getScreenY());
                }
            });
            path.setOnMouseReleased(event -> mouseLocation.value = null);
    
    
            // Drag on scene (i.e not on path, i.e. on transparent part) - move transparent part
            root.setOnDragDetected(event -> {
                mouseLocation.value = new Point2D(event.getScreenX(), event.getScreenY());
            });
            root.setOnMouseDragged(event -> {
                if (mouseLocation.value != null) {
                    innerLeft.set(innerLeft.get() + event.getScreenX() - mouseLocation.value.getX());
                    innerTop.set(innerTop.get() + event.getScreenY() - mouseLocation.value.getY());
                    mouseLocation.value = new Point2D(event.getScreenX(), event.getScreenY());
                }
            });
            root.setOnMouseReleased(event -> mouseLocation.value = null);
    
            // No close button on a transparent window, so exit on double click:
            root.setOnMouseClicked(event -> {
                if (event.getClickCount() == 2) Platform.exit();
                event.consume();
            });
    
            Scene scene = new Scene(root, 800, 600);
    
            scene.setFill(Color.TRANSPARENT);
            stage.initStyle(StageStyle.TRANSPARENT);
            stage.setScene(scene);
            stage.show();
        }
    
        private PathElement createBoundLineTo(ObservableDoubleValue x, ObservableDoubleValue y) {
            LineTo lineTo = new LineTo();
            lineTo.xProperty().bind(x);
            lineTo.yProperty().bind(y);
            return lineTo ;
        }
    
        private PathElement createBoundLineTo(double fixedX, ObservableDoubleValue y) {
            LineTo lineTo = new LineTo();
            lineTo.setX(fixedX);
            lineTo.yProperty().bind(y);
            return lineTo ;
        }
    
        private PathElement createBoundLineTo(ObservableDoubleValue x, double fixedY) {
            LineTo lineTo = new LineTo();
            lineTo.setY(fixedY);
            lineTo.xProperty().bind(x);
            return lineTo ;
        }
    
        public static void main(String[] args) {
            launch(args);
        }
    }
    

    【讨论】:

    • 不错的方法,非常感谢。我现在可以向前编码,但有两点:1.如何调整透明区域的大小 2.我可以拖动透明区域的区域很难获得。我怎样才能让它更大?
    • 要使内部区域可调整大小,请为innerRightinnerBottom 创建常规属性(不要将它们绑定到innerLeftinnerTop)。然后您可以独立操作它们,从而改变大小。不太确定我是否理解第二个问题,但在此示例中,总面积仅由场景大小定义 (new Scene(root, 800, 600))。
    • 好的,第一个,我试试,第二个,我将内部透明度更改为蓝色,看看它是如何工作的。在透明的情况下,很难拖动内部区域。
    猜你喜欢
    • 1970-01-01
    • 2017-03-09
    • 2011-09-16
    • 1970-01-01
    • 1970-01-01
    • 2023-04-01
    • 1970-01-01
    • 2021-04-27
    • 1970-01-01
    相关资源
    最近更新 更多