如何隐藏场景之外的元素部分? JavaFX

How I can hide the part of element that is outside of Scene? JavaFX

这种情况很难解释,我会尽力而为。

我需要做一个圆形窗格或场景来隐藏圆形区域之外的元素(节点)部分。我的意思是,我不想只隐藏外部区域的完整元素。就像一个“.setClip”。我不能使用最后一种方法,因为该项目是一个动画,当我移动节点时,剪辑也会移动。

当文字出现时,这就是我想要制作的。

Example

这是我项目中的一张图片。红色的标记说明了问题。

谢谢!

PD:这是 DocumentController Link

setClip() 有什么问题?如果以下没有给您所需的答案,请提供一个完整的代码示例来说明问题。

剪辑图像(即没有文字)

import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.SnapshotParameters;
import javafx.scene.control.Label;
import javafx.scene.effect.DropShadow;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.text.Font;
import javafx.stage.Stage;

public class ClipImage extends Application {

    @Override
    public void start(Stage primaryStage) {

        Group root = new Group();

        // background image
        ImageView imageView = new ImageView( "http://upload.wikimedia.org/wikipedia/commons/thumb/4/41/Siberischer_tiger_de_edit02.jpg/800px-Siberischer_tiger_de_edit02.jpg");

        // some text
        Label label = new Label( "This is a Tiger. Tigers are awesome!");
        label.relocate(20, 400);
        label.setTextFill(Color.RED);
        label.setFont(new Font("Tahoma", 48));

        root.getChildren().addAll( imageView, label);

        Scene scene = new Scene( root, 1024, 768);

        primaryStage.setScene( scene);
        primaryStage.show();

        // pane with clipped area
        CirclePane circlePane = new CirclePane();
        makeDraggable( circlePane);

        root.getChildren().addAll( circlePane);

    }

    public static void main(String[] args) {
        launch(args);
    }


    private class CirclePane extends Pane {

        public CirclePane() {

            // load image
//          ImageView imageView = new ImageView( getClass().getResource("tiger.jpg").toExternalForm());
            ImageView imageView = new ImageView( "http://upload.wikimedia.org/wikipedia/commons/thumb/4/41/Siberischer_tiger_de_edit02.jpg/800px-Siberischer_tiger_de_edit02.jpg");

            // create circle
            Circle circle = new Circle( 200);
            circle.relocate(200, 100);

            // clip image by circle
            imageView.setClip(circle);

            // non-clip area should be transparent
            SnapshotParameters parameters = new SnapshotParameters();
            parameters.setFill(Color.TRANSPARENT); 

            // new image from clipped image
            WritableImage wim = null;
            wim = imageView.snapshot(parameters, wim);

            // new imageview
            ImageView clippedView = new ImageView( wim);

            // some shadow
            clippedView.setEffect(new DropShadow(15, Color.BLACK));

            clippedView.relocate( 200, 100);

            getChildren().addAll( clippedView);

        }

    }

    // make node draggable
    class DragContext { 
        double x;
        double y; 
    } 

    public void makeDraggable( Node node) {

        final DragContext dragDelta = new DragContext();

        node.setOnMousePressed(mouseEvent -> {

            dragDelta.x = node.getBoundsInParent().getMinX() - mouseEvent.getScreenX();
            dragDelta.y = node.getBoundsInParent().getMinY() - mouseEvent.getScreenY();

        });

        node.setOnMouseDragged(mouseEvent -> node.relocate( mouseEvent.getScreenX() + dragDelta.x, mouseEvent.getScreenY() + dragDelta.y));

    }


}

只需点击脸部并四处拖动即可。

或者您拍摄整个场景并对其进行剪辑,这样您就拥有了新图像中的所有内容:

import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.SnapshotParameters;
import javafx.scene.control.Label;
import javafx.scene.effect.DropShadow;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.text.Font;
import javafx.stage.Stage;

public class ClipScene extends Application {

    Stage primaryStage;

    @Override
    public void start(Stage primaryStage) {

        this.primaryStage = primaryStage;

        Group root = new Group();

        // background image
//      ImageView imageView = new ImageView( getClass().getResource("tiger.jpg").toExternalForm());
        ImageView imageView = new ImageView( "http://upload.wikimedia.org/wikipedia/commons/thumb/4/41/Siberischer_tiger_de_edit02.jpg/800px-Siberischer_tiger_de_edit02.jpg");

        // some text
        Label label = new Label( "This is a Tiger. Tigers are awesome!");
        label.relocate(20, 400);
        label.setTextFill(Color.RED);
        label.setFont(new Font("Tahoma", 48));

        root.getChildren().addAll( imageView, label);

        Scene scene = new Scene( root, 1024, 768);

        primaryStage.setScene( scene);
        primaryStage.show();

        // pane with clipped area
        CirclePane circlePane = new CirclePane();
        makeDraggable( circlePane);

        root.getChildren().addAll( circlePane);

    }

    public static void main(String[] args) {
        launch(args);
    }


    private class CirclePane extends Pane {

        public CirclePane() {

            WritableImage wim = null;

            // load image
            wim = primaryStage.getScene().snapshot( wim);

            // create imageview
            ImageView imageView = new ImageView( wim);

            // create circle
            Circle circle = new Circle( 200);
            circle.relocate(200, 100);

            // clip image by circle
            imageView.setClip(circle);

            // non-clip area should be transparent
            SnapshotParameters parameters = new SnapshotParameters();
            parameters.setFill(Color.TRANSPARENT); 

            // new image from clipped image
            wim = imageView.snapshot(parameters, wim);

            // new imageview
            ImageView clippedView = new ImageView( wim);

            // some shadow
            clippedView.setEffect(new DropShadow(15, Color.BLACK));

            clippedView.relocate( 200, 100);

            getChildren().addAll( clippedView);

        }

    }

    // make node draggable
    class DragContext { 
        double x;
        double y; 
    } 

    public void makeDraggable( Node node) {

        final DragContext dragDelta = new DragContext();

        node.setOnMousePressed(mouseEvent -> {

            dragDelta.x = node.getBoundsInParent().getMinX() - mouseEvent.getScreenX();
            dragDelta.y = node.getBoundsInParent().getMinY() - mouseEvent.getScreenY();

        });

        node.setOnMouseDragged(mouseEvent -> node.relocate( mouseEvent.getScreenX() + dragDelta.x, mouseEvent.getScreenY() + dragDelta.y));

    }


}

这是背景垂直滚动的动画版本:

import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.SnapshotParameters;
import javafx.scene.effect.DropShadow;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;

public class ClipImage extends Application {

    Stage primaryStage;

    @Override
    public void start(Stage primaryStage) {

        this.primaryStage = primaryStage;

        Group root = new Group();

        // background image
        ImageView imageView = new ImageView( "http://upload.wikimedia.org/wikipedia/commons/thumb/5/58/Sunset_2007-1.jpg/640px-Sunset_2007-1.jpg");

        root.getChildren().addAll( imageView);

        Scene scene = new Scene( root, 1024, 768);

        primaryStage.setScene( scene);
        primaryStage.show();

        // pane with clipped area
        CirclePane circlePane = new CirclePane();
        makeDraggable( circlePane);

        root.getChildren().addAll( circlePane);

        AnimationTimer timer = new AnimationTimer() {

            @Override
            public void handle(long now) {
                circlePane.scroll();                
            }

        };
        timer.start();
    }

    public static void main(String[] args) {
        launch(args);
    }


    private class CirclePane extends Pane {

        double y = 0;
        ImageView clippedView;
        ImageView imageView;
        Circle circle;
        SnapshotParameters parameters;
        WritableImage wim = null;

        boolean directionForward = true;

        public CirclePane() {

            imageView = new ImageView( "http://upload.wikimedia.org/wikipedia/commons/thumb/5/58/Sunset_2007-1.jpg/640px-Sunset_2007-1.jpg");

            // create circle
            circle = new Circle( 100);
            circle.relocate(200, 100);

            // clip image by circle
            imageView.setClip(circle);

            // non-clip area should be transparent
            parameters = new SnapshotParameters();
            parameters.setFill(Color.TRANSPARENT); 

            // new image from clipped image
            wim = null;
            wim = imageView.snapshot(parameters, wim);

            // new imageview
            clippedView = new ImageView( wim);

            // some shadow
            clippedView.setEffect(new DropShadow(15, Color.BLACK));

            clippedView.relocate( 150, 100);

            getChildren().addAll( clippedView);

        }

        public void scroll() {

            if( directionForward) {
                y++;
                if( y > 100) {
                    directionForward = false;
                }
            } else {
                y--;
                if( y < 0) {
                    directionForward = true;
                }
            }

            circle.relocate(150, 100 + y);
            imageView.setClip(circle);
            wim = imageView.snapshot(parameters, wim);
            clippedView.setImage( wim);
        }

    }

    // make node draggable
    class DragContext { 
        double x;
        double y; 
    } 

    public void makeDraggable( Node node) {

        final DragContext dragDelta = new DragContext();

        node.setOnMousePressed(mouseEvent -> {

            dragDelta.x = node.getBoundsInParent().getMinX() - mouseEvent.getScreenX();
            dragDelta.y = node.getBoundsInParent().getMinY() - mouseEvent.getScreenY();

        });

        node.setOnMouseDragged(mouseEvent -> node.relocate( mouseEvent.getScreenX() + dragDelta.x, mouseEvent.getScreenY() + dragDelta.y));

    }


}

和文本一样,其中场景用于创建图像视图和标签的组合快照。

import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.SnapshotParameters;
import javafx.scene.control.Label;
import javafx.scene.effect.DropShadow;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.text.Font;
import javafx.stage.Stage;

public class ClipScene extends Application {

    Stage primaryStage;

    @Override
    public void start(Stage primaryStage) {

        this.primaryStage = primaryStage;

        Group root = new Group();

        // background image
        ImageView imageView = new ImageView( "http://upload.wikimedia.org/wikipedia/commons/thumb/5/58/Sunset_2007-1.jpg/640px-Sunset_2007-1.jpg");

        // some text
        Label label = new Label( "Let the sun shine!");
        label.relocate(180, 220);
        label.setTextFill(Color.YELLOW);
        label.setFont(new Font("Tahoma", 18));

        root.getChildren().addAll( imageView, label);

        Scene scene = new Scene( root, 1024, 768);

        primaryStage.setScene( scene);
        primaryStage.show();

        // pane with clipped area
        CirclePane circlePane = new CirclePane();
        makeDraggable( circlePane);

        root.getChildren().addAll( circlePane);

//      label.setVisible(false);
//      imageView.setVisible(false);

        AnimationTimer timer = new AnimationTimer() {

            @Override
            public void handle(long now) {
                circlePane.scroll();                
            }

        };
        timer.start();
    }

    public static void main(String[] args) {
        launch(args);
    }


    private class CirclePane extends Pane {

        double y = 0;
        ImageView clippedView;
        ImageView imageView;
        Circle circle;
        SnapshotParameters parameters;
        WritableImage wim = null;

        boolean direction = true;

        public CirclePane() {

            WritableImage wim = null;

            // load image
            wim = primaryStage.getScene().snapshot( wim);

            imageView = new ImageView( wim);

            // create circle
            circle = new Circle( 100);
            circle.relocate(200, 100);

            // clip image by circle
            imageView.setClip(circle);

            // non-clip area should be transparent
            parameters = new SnapshotParameters();
            parameters.setFill(Color.TRANSPARENT); 

            // new image from clipped image
            wim = null;
            wim = imageView.snapshot(parameters, wim);

            // new imageview
            clippedView = new ImageView( wim);

            // some shadow
            clippedView.setEffect(new DropShadow(15, Color.BLACK));

            clippedView.relocate( 150, 100);

            getChildren().addAll( clippedView);

        }

        public void scroll() {

            if( direction) {
                y++;
                if( y > 100) {
                    direction = false;
                }
            } else {
                y--;
                if( y < 0) {
                    direction = true;
                }
            }

            circle.relocate(150, 100 + y);
            imageView.setClip(circle);
            wim = imageView.snapshot(parameters, wim);
            clippedView.setImage( wim);
        }

    }

    // make node draggable
    class DragContext { 
        double x;
        double y; 
    } 

    public void makeDraggable( Node node) {

        final DragContext dragDelta = new DragContext();

        node.setOnMousePressed(mouseEvent -> {

            dragDelta.x = node.getBoundsInParent().getMinX() - mouseEvent.getScreenX();
            dragDelta.y = node.getBoundsInParent().getMinY() - mouseEvent.getScreenY();

        });

        node.setOnMouseDragged(mouseEvent -> node.relocate( mouseEvent.getScreenX() + dragDelta.x, mouseEvent.getScreenY() + dragDelta.y));

    }


}

这里是所有组合,动画日落在屏幕外 "rendered",即我们使用窗格作为快照,而不是场景:

import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.SnapshotParameters;
import javafx.scene.control.Label;
import javafx.scene.effect.DropShadow;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.stage.Stage;

public class ClipOffScreen extends Application {

    @Override
    public void start(Stage primaryStage) {

        Group root = new Group();

        // background image
        ImageView imageView = new ImageView( "http://upload.wikimedia.org/wikipedia/commons/thumb/4/41/Siberischer_tiger_de_edit02.jpg/800px-Siberischer_tiger_de_edit02.jpg");

        // some text
        Label label = new Label( "This is a Tiger. Tigers are awesome!");
        label.relocate(20, 400);
        label.setTextFill(Color.RED);
        label.setFont(new Font("Tahoma", 48));

        root.getChildren().addAll( imageView, label);

        Scene scene = new Scene( root, 1024, 768);

        primaryStage.setScene( scene);
        primaryStage.show();

        // pane with clipped area
        CirclePane circlePane = new CirclePane();
        makeDraggable( circlePane);

        root.getChildren().addAll( circlePane);

        AnimationTimer timer = new AnimationTimer() {

            @Override
            public void handle(long now) {
                circlePane.scroll();                
            }

        };
        timer.start();
    }

    public static void main(String[] args) {
        launch(args);
    }


    private class CirclePane extends Pane {

        double y = 0;
        ImageView clippedView;
        ImageView imageView;
        Circle circle;
        SnapshotParameters parameters;
        WritableImage wim = null;

        boolean direction = true;

        public CirclePane() {

            Pane offScreenPane = new Pane();

            // background image
            ImageView imageView2 = new ImageView( "http://upload.wikimedia.org/wikipedia/commons/thumb/5/58/Sunset_2007-1.jpg/640px-Sunset_2007-1.jpg");

            // some text
            Text text = new Text( "Let the sun shine!");
            text.relocate(180, 220);
            text.setFill(Color.YELLOW);
            text.setFont(new Font("Tahoma", 18));

            offScreenPane.getChildren().addAll( imageView2, text);

            // non-clip area should be transparent
            parameters = new SnapshotParameters();
            parameters.setFill(Color.TRANSPARENT); 

            WritableImage wim = null;

            // load image
            wim = offScreenPane.snapshot( parameters, wim);

            imageView = new ImageView( wim);

            // create circle
            circle = new Circle( 100);
            circle.relocate(200, 100);

            // clip image by circle
            imageView.setClip(circle);



            // new image from clipped image
            wim = null;
            wim = imageView.snapshot(parameters, wim);

            // new imageview
            clippedView = new ImageView( wim);

            // some shadow
            clippedView.setEffect(new DropShadow(15, Color.BLACK));

            clippedView.relocate( 150, 100);

            getChildren().addAll( clippedView);

        }

        public void scroll() {

            if( direction) {
                y++;
                if( y > 100) {
                    direction = false;
                }
            } else {
                y--;
                if( y < 0) {
                    direction = true;
                }
            }

            circle.relocate(150, 100 + y);
            imageView.setClip(circle);
            wim = imageView.snapshot(parameters, wim);
            clippedView.setImage( wim);
        }

    }

    // make node draggable
    class DragContext { 
        double x;
        double y; 
    } 

    public void makeDraggable( Node node) {

        final DragContext dragDelta = new DragContext();

        node.setOnMousePressed(mouseEvent -> {

            dragDelta.x = node.getBoundsInParent().getMinX() - mouseEvent.getScreenX();
            dragDelta.y = node.getBoundsInParent().getMinY() - mouseEvent.getScreenY();

        });

        node.setOnMouseDragged(mouseEvent -> node.relocate( mouseEvent.getScreenX() + dragDelta.x, mouseEvent.getScreenY() + dragDelta.y));

    }


}

诀窍是使用文本而不是标签,因为如果标签不可见,标签将被隐藏。我猜这是某种 JavaFX 内部优化。