Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JavaFX inverse-clipping and clipping using text?

So far all I've been able to find regarding clipping in JavaFX is the Node.setClip(Node value) method. This forces a Node to render only within the boundaries of the given Node. I want to do the reverse of that--cut out part of a Node based on the shape of the second one, in particular text. In (mostly) pseudocode:

Rectangle rect = new Rectangle(0, 0, 160, 90);
Label cutOutText = new Label("YAY");
rect.setFill(Color.RED);
rect.setInverseClip(cutOutText);

This would result in (on a white background)...

The resulting rectangle, with punched-out text.

Another example:

enter image description here

like image 310
Sam Claus Avatar asked Oct 18 '22 21:10

Sam Claus


1 Answers

There is no built-in method for this as far as I know. However, here is an example of what you are trying to achive using Shapes:

package application;

import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.ProgressBar;
import javafx.scene.effect.InnerShadow;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.StackPane;
import javafx.scene.shape.Rectangle;
import javafx.scene.shape.Shape;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.stage.Stage;


public class Main extends Application {
    @Override
    public void start(final Stage primaryStage) {
        final StackPane root = new StackPane();
        final ProgressBar bar = new ProgressBar();
        final Image image = new Image( "https://farm8.staticflickr.com/7036/6952932649_3fc1cfeb8a_o_d.jpg", true );
        final ImageView imageView = new ImageView( image );
        final Text clip = new Text( "JavaFx" );
        final Scene scene = new Scene( root );

        root.setStyle( "-fx-background: pink;" );
        root.setEffect( new InnerShadow() );

        bar.prefWidthProperty().bind( root.widthProperty() );
        bar.visibleProperty().bind( Bindings.notEqual( 1, image.progressProperty() ) );
        bar.progressProperty().bind( image.progressProperty() );

        imageView.setFitWidth( 800 );
        imageView.setFitHeight( 600 );

        clip.setFont( Font.font( 144.0 ) );
    clip.setX( 400 - clip.getBoundsInLocal().getWidth() / 2 );
        clip.setY( 400 - clip.getBoundsInLocal().getHeight() / 2 );

        setInverseClip( imageView, clip );

        root.getChildren().add( bar );
        root.getChildren().add( imageView );

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

    private void setInverseClip( final Node node, final Shape clip ) {
        final Rectangle inverse = new Rectangle();
        inverse.setWidth( node.getLayoutBounds().getWidth() );
        inverse.setHeight( node.getLayoutBounds().getHeight() );
        node.setClip( Shape.subtract( inverse, clip ) );
    }

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

}

It overlays the target node with an rectangle of the same size, subtracts the original clip node from it, and uses the newly created shape as the clip to the target node.

like image 172
Oliver Jan Krylow Avatar answered Oct 21 '22 16:10

Oliver Jan Krylow