Robert K
Robert K

Reputation: 488

JavaFX Label doesn't center if not wrapped

I've encountered a very strange set of circumstances with text wrapping and centered alignment in a JavaFX label. I'm sure I'm doing something wrong or ill-advised, but I cannot seem to figure out what I'm doing wrong.

Basically, I'm attempting to put a title over a tile pane, and have that title be centered. Also, when the window is resized, I'd like the title to wrap. The strangeness comes in when the title is not wrapped (e.g.: one line), it isn't centered any more. As soon as it wraps, it centers again. Here's some sample code that produces the effect:

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.TilePane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

import org.apache.commons.lang.RandomStringUtils;
public class Foo extends Application
{
    @Override
    public void start(Stage primaryStage) throws Exception
    {
        TilePane panel = new TilePane();
        panel.setTileAlignment(Pos.CENTER_LEFT);

        for (int i = 0; i < 25; i++)
        {
            panel.getChildren().add(new Label(RandomStringUtils.randomAlphabetic(10)));
        }

        Label title = new Label("Lorem ipsum dolor sit amet, consectetur adipiscing elit");
        title.setStyle("-fx-font-size: 16; -fx-font-weight: bold; -fx-wrap-text:true; -fx-text-alignment: center -fx-border-color:black;");
        title.minWidthProperty().bind(Bindings.add(-30, primaryStage.widthProperty()));
        title.setTextAlignment(TextAlignment.CENTER);

        VBox box = new VBox(title, panel);
        box.setPadding(new Insets(10));

        primaryStage.setScene(new Scene(box, 400, 400));
        primaryStage.show();

    }

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

Here's a screenshot of what I'm seeing. In the first one, the bold line on top is centered and wrapped. In the second one, the bold line on top is not wrapped, and is left-aligned.

wrapped and centered not wrapped and not centered

Upvotes: 2

Views: 5914

Answers (2)

James_D
James_D

Reputation: 209319

As stated in the documentation, the text alignment controls the alignment of multi-line text. This is exactly the specified behavior.

If you imagine a rectangle that bounds all the text, when the text has multiple lines a decision has to be made as to how these individual lines are laid out within that rectangle. This is controlled by the textAlignment property. The default is to align each line to the left of that box: you can also center, right-align, or justify (expand each line to fill the box). Another way to think of this is that the textAlignment only controls the position of each line of text relative to the other lines of text.

On the other hand, the alignment property defines how the content of the label (text and graphic) is aligned within the label itself, if there is more space in the label than the text occupies. So to center the label in your VBox you first need to ensure the label fills the complete width of the VBox, and then you need to set the alignment property to CENTER. You do the former by setting the maxWidth of the label so that it grows indefinitely, and setting the fillWidth() property of the VBox to true.

Using Java this looks like

public void start(Stage primaryStage) throws Exception
{
    TilePane panel = new TilePane();
    panel.setTileAlignment(Pos.CENTER_LEFT);

    for (int i = 0; i < 25; i++)
    {
        panel.getChildren().add(new Label(randomAlphabetic(10)));
    }

    Label title = new Label("Lorem ipsum dolor sit amet, consectetur adipiscing elit");
    title.setStyle("-fx-font-size: 16; -fx-font-weight: bold; -fx-wrap-text:true; -fx-border-color:black;");

        title.setPadding(new Insets(5));
        title.setAlignment(Pos.CENTER);
        title.setMaxWidth(Double.MAX_VALUE);


    title.setTextAlignment(TextAlignment.CENTER);

    VBox box = new VBox(title, panel);
    box.setFillWidth(true); 

    box.setPadding(new Insets(10));

    primaryStage.setScene(new Scene(box, 400, 400));
    primaryStage.show();

}

and you can set these properties in CSS if you prefer:

@Override
public void start(Stage primaryStage) throws Exception
{
    TilePane panel = new TilePane();
    panel.setTileAlignment(Pos.CENTER_LEFT);

    for (int i = 0; i < 25; i++)
    {
        panel.getChildren().add(new Label(randomAlphabetic(10)));
    }

    Label title = new Label("Lorem ipsum dolor sit amet, consectetur adipiscing elit");
    title.setStyle("-fx-font-size: 16; -fx-font-weight: bold; -fx-wrap-text:true; -fx-border-color:black;"
            + "-fx-text-alignment: center; -fx-alignment: center; -fx-max-width:Infinity; -fx-padding: 5;");


    VBox box = new VBox(title, panel);
    box.setFillWidth(true); // or box.setStyle("-fx-fill-width: true ;")

    box.setPadding(new Insets(10));

    primaryStage.setScene(new Scene(box, 400, 400));
    primaryStage.show();

}

Upvotes: 6

jonaslagoni
jonaslagoni

Reputation: 818

Allright i try a some different tacticts and I figured it out with regular css. You can use the "-fx-alignment: center;" to do it. See this link for more information about which kind of css to use. Also the width of the label is important, else the width will just be the length of the text and there would be nothing to really center.

Making the changes, your code will look like this

@Override
public void start(Stage primaryStage) throws Exception
{
    TilePane panel = new TilePane();
    panel.setTileAlignment(Pos.CENTER_LEFT);

    for (int i = 0; i < 25; i++)
    {
        panel.getChildren().add(new Label(RandomStringUtils.randomAlphabetic(10)));
    }

    Label title = new Label("Lorem ipsum dolor sit amet, consectetur adipiscing elit");
    title.setStyle("-fx-font-size: 16; -fx-font-weight: bold; -fx-wrap-text:true; -fx-alignment: center; -fx-border-color:black;");
    title.setMinWidth(400); //This is important, else the width will just be the text's length

    VBox box = new VBox(title, panel);
    box.setPadding(new Insets(10));

    primaryStage.setScene(new Scene(box, 400, 400));
    primaryStage.show();

}

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

Upvotes: -1

Related Questions