Andy Till
Andy Till

Reputation: 3511

Drawing a border around a JavaFX Text node

I want to draw red borders around arbitrary javafx.scene.text.Text nodes in my JavaFX scenegraph, for example those in a Button object.

It is easy to retrieve all the Text nodes but not to find where they are in the scene, they have an x and y property which doesn't seem to get set properly but they do not have a width and height.

So far I have tried to add rectangles with a red stroke to a stack pane but the x and y are always wrong and I can't get the size.

Upvotes: 4

Views: 19077

Answers (1)

James_D
James_D

Reputation: 209724

One solution is to wrap the text nodes in layout pane (such as an HBox) and use CSS on the layout pane:

import javafx.application.Application;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.layout.HBox;
import javafx.scene.text.Text;
import javafx.stage.Stage;

public class TextBorderExample extends Application {

    @Override
    public void start(Stage primaryStage) {
        final HBox root = new HBox(5);

        root.getChildren().addAll(
                new Text("This"), new Text("Is"), new Text("A"), createBorderedText("Red"), new Text("Bordered"), new Text("Text")
        );

        primaryStage.setScene(new Scene(root));
        primaryStage.show();
    }
    private Node createBorderedText(String text) {
        final HBox hbox = new HBox();
        hbox.getChildren().add(new Text(text));
        hbox.setStyle("-fx-border-color: red;");
        return hbox ;
    }

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

Another way is to use a Rectangle, as follows:

import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.geometry.Bounds;
import javafx.scene.Scene;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Text;
import javafx.stage.Stage;

public class TextBorderExample extends Application {

    @Override
    public void start(Stage primaryStage) {
        final HBox root = new HBox(5);
        final Text red = new Text("Red");
        final Rectangle redBorder = new Rectangle(0, 0, Color.TRANSPARENT);
        redBorder.setStroke(Color.RED);
        redBorder.setManaged(false);
        red.boundsInParentProperty().addListener(new ChangeListener<Bounds>() {

            @Override
            public void changed(ObservableValue<? extends Bounds> observable,
                    Bounds oldValue, Bounds newValue) {
                redBorder.setLayoutX(red.getBoundsInParent().getMinX());
                redBorder.setLayoutY(red.getBoundsInParent().getMinY());
                redBorder.setWidth(red.getBoundsInParent().getWidth());
                redBorder.setHeight(red.getBoundsInParent().getHeight());
            }

        });
        root.getChildren().addAll(new Text("This"), new Text("Is"), new Text("A"), red, new Text("Bordered"), new Text("Text"));
        root.getChildren().add(redBorder);


        primaryStage.setScene(new Scene(root));
        primaryStage.show();
    }

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

Upvotes: 8

Related Questions