Search code examples
javafxclippingborderpane

How to clip and resize javafx borderpane


I am just starting with JavaFX. I want to have a BorderPane with controls on top, left, and right, and an image in the center. I want the center pane to resize as you resize the window, but to always be able to see all left, right, and top controls.

With the code below, I can show a button in the left, top, and right. And I can display an image in the center.

But the image expands beyond center bounds and hides the right button.

Oddly, if I set a clipping rectangle on the imageview in the center pane (uncomment lines 67 & 68), it does in fact only draw the clipped region, but the rest of the layout behaves as if it were drawing the whole picture. That is, the UNDRAWN part of the image still obscures the button on the right.

Any help would be much appreciated.

Thanks in advance and apologies if it's simple.

import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.image.*;
import javafx.scene.layout.*;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;

public class ImageApp extends Application {
    private BorderPane root;
    private Rectangle clipRect;
    private ImageView iv;
    private StackPane leftPane;
    private StackPane rightPane;
    private Button topButton;
    private Button leftButton;
    private Button rightButton;

    @Override
    public void start(Stage primaryStage) {
        root = new BorderPane();
        Scene primaryScene = new Scene(root, 900, 800);
        initializePrimaryStage(primaryStage, primaryScene);
        initializeFrameContent(root, topButton, leftButton);
        initializeContent(root);
        primaryStage.show();
    }

    private void initializeFrameContent(BorderPane root, Button topButton, Button leftButton) {

        topButton = new Button("TOP");
        leftButton = new Button("LEFT");
        rightButton = new Button("RIGHT");

        leftPane = new StackPane(leftButton);
        leftPane.setAlignment(Pos.TOP_LEFT);

        rightPane = new StackPane(rightButton);
        rightPane.setAlignment(Pos.TOP_RIGHT);

        root.setLeft(leftPane);
        root.setTop(topButton);
        root.setRight(rightButton);
    }

    private void initializePrimaryStage(Stage primaryStage, Scene   primaryScene) {
        primaryStage.setTitle("Image Clip Test");
        primaryStage.setScene(primaryScene);
        primaryStage.setWidth(400);
        primaryStage.setHeight(300);
        primaryStage.minWidthProperty().setValue(400);
        primaryStage.minHeightProperty().setValue(300);
    }

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

    }

    private void initializeContent(BorderPane root) {
        Image image = new Image(
                "http://www.ciee.org/study-abroad/images/cities/0020/headers/desktop/big-ben-london-traffic-trafalgar-abroad-studies.jpg"
        );
        iv = new ImageView(image);
        root.setCenter(iv);
        //clipRect = new Rectangle(400,200);
        //root.getCenter().setClip(clipRect);
    }
}

Solution

  • You don't specify what you intend to do. Why would you want to clip the content? The way you describe it all you want is some background that's getting clipped. You can do that with various mechanisms, e. g. css.

    Or you could use a proper parent, e. g. a ScrollPane in order to limit the region or e. g. an ImageViewPane in order to stretch to fit:

    import javafx.application.Application;
    import javafx.beans.property.ObjectProperty;
    import javafx.beans.property.SimpleObjectProperty;
    import javafx.beans.value.ChangeListener;
    import javafx.beans.value.ObservableValue;
    import javafx.geometry.HPos;
    import javafx.geometry.Pos;
    import javafx.geometry.VPos;
    import javafx.scene.Scene;
    import javafx.scene.control.Button;
    import javafx.scene.image.Image;
    import javafx.scene.image.ImageView;
    import javafx.scene.layout.BorderPane;
    import javafx.scene.layout.Region;
    import javafx.scene.layout.StackPane;
    import javafx.scene.shape.Rectangle;
    import javafx.stage.Stage;
    
    public class ImageApp extends Application {
        private BorderPane root;
        private Rectangle clipRect;
        private ImageView iv;
        private StackPane leftPane;
        private StackPane rightPane;
        private Button topButton;
        private Button leftButton;
        private Button rightButton;
    
        @Override
        public void start(Stage primaryStage) {
            root = new BorderPane();
            Scene primaryScene = new Scene(root, 900, 800);
            initializePrimaryStage(primaryStage, primaryScene);
            initializeFrameContent(root, topButton, leftButton);
            initializeContent(root);
            primaryStage.show();
        }
    
        private void initializeFrameContent(BorderPane root, Button topButton, Button leftButton) {
    
            topButton = new Button("TOP");
            leftButton = new Button("LEFT");
            rightButton = new Button("RIGHT");
    
            leftPane = new StackPane(leftButton);
            leftPane.setAlignment(Pos.TOP_LEFT);
    
            rightPane = new StackPane(rightButton);
            rightPane.setAlignment(Pos.TOP_RIGHT);
    
            root.setLeft(leftPane);
            root.setTop(topButton);
            root.setRight(rightButton);
        }
    
        private void initializePrimaryStage(Stage primaryStage, Scene   primaryScene) {
            primaryStage.setTitle("Image Clip Test");
            primaryStage.setScene(primaryScene);
            primaryStage.setWidth(400);
            primaryStage.setHeight(300);
            primaryStage.minWidthProperty().setValue(400);
            primaryStage.minHeightProperty().setValue(300);
        }
    
        public static void main(String[] args) {
            launch(args);
    
        }
    
        private void initializeContent(BorderPane root) {
    
            Image image = new Image(
                    "http://www.ciee.org/study-abroad/images/cities/0020/headers/desktop/big-ben-london-traffic-trafalgar-abroad-studies.jpg"
            );
            iv = new ImageView(image);
    
            // ImageViewPane content = new ImageViewPane( iv);
            ScrollPane content = new ScrollPane( imageView);
    
            // hide scrollbars
            content.setVbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
            content.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
            content.setPadding(Insets.EMPTY);
    
            root.setCenter(content);
        }
    
    
        // code from here: https://stackoverflow.com/questions/22993550/how-to-resize-an-image-when-resizing-the-window-in-javafx
        class ImageViewPane extends Region {
    
            private ObjectProperty<ImageView> imageViewProperty = new SimpleObjectProperty<ImageView>();
    
            public ObjectProperty<ImageView> imageViewProperty() {
                return imageViewProperty;
            }
    
            public ImageView getImageView() {
                return imageViewProperty.get();
            }
    
            public void setImageView(ImageView imageView) {
                this.imageViewProperty.set(imageView);
            }
    
            public ImageViewPane() {
                this(new ImageView());
            }
    
            @Override
            protected void layoutChildren() {
                ImageView imageView = imageViewProperty.get();
                if (imageView != null) {
                    imageView.setFitWidth(getWidth());
                    imageView.setFitHeight(getHeight());
                    layoutInArea(imageView, 0, 0, getWidth(), getHeight(), 0, HPos.CENTER, VPos.CENTER);
                }
                super.layoutChildren();
            }
    
            public ImageViewPane(ImageView imageView) {
                imageViewProperty.addListener(new ChangeListener<ImageView>() {
    
                    @Override
                    public void changed(ObservableValue<? extends ImageView> arg0, ImageView oldIV, ImageView newIV) {
                        if (oldIV != null) {
                            getChildren().remove(oldIV);
                        }
                        if (newIV != null) {
                            getChildren().add(newIV);
                        }
                    }
                });
                this.imageViewProperty.set(imageView);
            }
        }
    }