user3133542
user3133542

Reputation: 1715

JavaFx: drawing a swing-like lowered etched Border possible?

How can I draw a Lower-Etched-Border in JavaFX similar to what is seen in a Swing label?

Upvotes: 2

Views: 2099

Answers (2)

jewelsea
jewelsea

Reputation: 159291

Sample based upon a Region extension coupled with an external CSS file.

This implementation allows the border to encompass arbitrary resizable content (including parent layout panes) if required. For example, you could place a StackPane containing content inside the BorderPane and use the "Optional Layout Constraints" of the StackPane to align the content and define margins for the content within the BorderPane (see the linked StackPane javadoc for an example of how to accomplish this).

Additionally, the style of the border itself can be customized from the external CSS file, so it should be possible to replicate any of the standard Swing borders (and other border styles) relatively easily.

Testing

border-pane.css

.border-pane {
    -fx-border-base: gray;
    -fx-border-shadow: white;
    -fx-light-border: derive(-fx-border-base, 25%);
    -fx-border-color: -fx-light-border -fx-border-base -fx-border-base -fx-light-border;
    -fx-border-insets: 0 1 1 0;
    -fx-background-color: -fx-border-shadow, -fx-background;
    -fx-background-insets: 1 0 0 1, 2;
    -fx-padding: 2;
}

LoweredEtchedBorderLabelBackgroundDemo.java

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

public class LoweredEtchedBorderDemo extends Application {

    @Override
    public void start(Stage stage) {
        Label label = new Label("Testing");
        label.setPadding(new Insets(10));

        // uncomment to see the area that the content node is taking up within the border.
        //label.setStyle("-fx-background-color: palegreen;");

        BorderPane borderPane = new BorderPane(new StackPane(label));

        // uncomment these two lines if you would like the border to resize to fit available space.
        borderPane.setMinSize(Region.USE_COMPUTED_SIZE, Region.USE_COMPUTED_SIZE);
        borderPane.setMaxSize(Region.USE_COMPUTED_SIZE, Region.USE_COMPUTED_SIZE);

        VBox layout = new VBox(borderPane);
        layout.setPadding(new Insets( 10));
        layout.setStyle("-fx-base: lightgrey;");
        VBox.setVgrow(borderPane, Priority.ALWAYS);

        Scene scene = new Scene(layout);

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

    private class BorderPane extends Region {
        // clip the bordered content within the bordered area.
        Rectangle clipRect = new Rectangle(getWidth(), getHeight());

        public BorderPane(Node content) {
            super();
            getChildren().add(content);

            getStylesheets().add(getClass().getResource(
                    "border-pane.css"
            ).toExternalForm());
            getStyleClass().add("border-pane");

            // by default size the border to the preferred size of the content.
            setMinSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE);
            setMaxSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE);

            content.setClip(clipRect);
        }

        @Override protected void layoutChildren() {
            final double width = getWidth();
            double height = getHeight();
            double top = getInsets().getTop();
            double right = getInsets().getRight();
            double left = getInsets().getLeft();
            double bottom = getInsets().getBottom();
            double contentWidth = width - left - right;
            double contentHeight = height - top - bottom;

            Node child = getManagedChildren().get(0);
            layoutInArea(child, left, top,
                    contentWidth, contentHeight,
                    0, null,
                    HPos.LEFT,
                    VPos.TOP);

            clipRect.setWidth(contentWidth);
            clipRect.setHeight(contentHeight);
        }
    }

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

}

Related Question

Upvotes: 2

Shekhar Rai
Shekhar Rai

Reputation: 2058

I researched for Lowered-Etched-Border for JavaFX but i didn't found any effective document. I also tested InnerShadow and other effects and those are not good fit for that. So i created a LEBLabel (subclass of Label) with that type of border-style.

public class LoweredEtchedBorderLabelDemo extends Application {

    @Override
    public void start(Stage primaryStage) {
        LEBLabel text = new LEBLabel("Testing", 200, 30);

        StackPane root = new StackPane();
        root.getChildren().add(text);
        root.setStyle("-fx-background-color:lightgrey");

        Scene scene = new Scene(root, 300, 250);

        primaryStage.setTitle("Lowered-Etched-Border Demo");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    //Lowered Etched Borderd Label
    private class LEBLabel extends Label {
        private HBox[] borders = new HBox[3];
        private String border_styles[] = {"-fx-border-width:0 1 1 0; -fx-border-color: white",
                                          "-fx-border-width:1; -fx-border-color:grey",
                                          "-fx-border-width:1 0 0 1; -fx-border-color:white"};

        public LEBLabel(String text, double width, double height) {
            super(text);
            for(int i = 0; i < borders.length; i++) {
                borders[i] = new HBox();
                borders[i].setStyle(border_styles[i]);

                //decrement of border-size for inner-border, prevents from the overlapping of border
                borders[i].setMaxSize(width - (1.5 *i), height - (1.5 * i));
                borders[i].setMinSize(width - (1.5 *i), height - (1.5 * i));

                borders[i].setSpacing(0);
            }
            this.setContentDisplay(ContentDisplay.CENTER);
            this.borders[1].getChildren().add(borders[2]);
            this.borders[0].getChildren().add(borders[1]);
            this.setGraphic(borders[0]);
        }       
    }

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

}

Note : This LEBLabel displays the text on Center-Side only so it ignores the Text-Alignment Properties.

Upvotes: 3

Related Questions