user1438038 user1438038 - 1 month ago 13
Java Question

JavaFX table with multiline, background color and centered text

In a JavaFX TableView, how can I


  • Create a multiline column?

  • Center its content?

  • And set background color for each (entire) line?



I managed to create a multiline column using a custom
CellFactory
. I'm also aware of
setAlignment(Pos.CENTER)
and
setTextAlignment(TextAlignment.CENTER)
to center text. However, the text in my sample app is not centered properly per line. Furthermore, I did not manage to set a background color on the
Text
objects. Now my approach is to add a
Pane
for each line, which works fine. But how do I make the
Pane
fill the column's entire width and 1/3rd of its height?

As a starting point, this is how I would expect the code to be (though, I'm aware it's not doing what I want):

multiCol.setCellFactory(new Callback<TableColumn<Person, Person>, TableCell<Person, Person>>() {
@Override public TableCell<Person, Person> call(TableColumn<Person, Person> multiCol) {
return new TableCell<Person, Person>() {
private Group grp = null;

@Override public void updateItem(final Person person, boolean empty) {
super.updateItem(person, empty);

this.setAlignment(Pos.CENTER);

if (!isEmpty()) {
Text text = new Text(person.getFirstName());
text.setX(0);
text.setY(0);
text.setTextAlignment(TextAlignment.CENTER); // Center text?

Pane pane = new Pane();
pane.setStyle("-fx-background-color: #66BB66;");
pane.setLayoutX(0);
pane.setLayoutY(0);
pane.setPrefHeight(20);
pane.setPrefWidth(this.prefWidth(-1)); // Column width?

// -----

Text text2 = new Text(person.getLastName());
text2.setX(0);
text2.setY(20);
text2.setTextAlignment(TextAlignment.CENTER); // Center text?

Pane pane2 = new Pane();
pane2.setStyle("-fx-background-color: #79A8D8;");
pane2.setLayoutX(0);
pane2.setLayoutY(20);
pane2.setPrefHeight(20);
pane2.setPrefWidth(this.prefWidth(-1)); // Column width?

// -----

Text text3 = new Text(person.getEmail());
text3.setX(0);
text3.setY(40);
text3.setTextAlignment(TextAlignment.CENTER); // Center text?

Pane pane3 = new Pane();
pane3.setStyle("-fx-background-color: #FF8888;");
pane3.setLayoutX(0);
pane3.setLayoutY(40);
pane3.setPrefHeight(20);
pane3.setPrefWidth(this.prefWidth(-1)); // Column width?

// -----

Group grp = new Group();

grp.getChildren().add(pane);
grp.getChildren().add(text);

grp.getChildren().add(pane2);
grp.getChildren().add(text2);

grp.getChildren().add(pane3);
grp.getChildren().add(text3);

setGraphic(grp);

setStyle("-fx-padding: 0 0 0 0;");
}
}
};
}
});


I'm expecting an output like this:
JavaFX TableView with multiline column

For a full, compilable code sample please check out this pastebin.

Answer

Use a suitable layout pane (e.g. a VBox), and add Labels to it. You can configure the labels to fill the width of a VBox using VBox.setHgrow(...). You also need to set the maximum width of the label to allow it to grow.

As an aside, it is not good practice to re-create the controls every time the updateItem(...) method is called. Create them once and then just configure them in the updateItem(...) method with the required data.

Example:

    TableColumn<Person, Person> multiCol = new TableColumn<>("Multiline");
    multiCol.setCellValueFactory(cellData -> 
        new ReadOnlyObjectWrapper<Person>(cellData.getValue()));
    multiCol.setCellFactory(column -> new TableCell<Person, Person>() {

        private VBox graphic ;
        private Label firstNameLabel ;
        private Label lastNameLabel ;
        private Label emailLabel ;

        // Anonymous constructor:
        {
            graphic = new VBox();
            firstNameLabel = createLabel("#66BB66");
            lastNameLabel = createLabel("#79A8D8");
            emailLabel = createLabel("#FF8888");
            graphic.getChildren().addAll(firstNameLabel, 
                    lastNameLabel, emailLabel);
            setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
        }

        private final Label createLabel(String color) {
            Label label = new Label();
            VBox.setVgrow(label, Priority.ALWAYS);
            label.setMaxWidth(Double.MAX_VALUE);
            label.setStyle("-fx-background-color: "+color+" ;");
            label.setAlignment(Pos.CENTER);
            return label ;
        }

        @Override
        public void updateItem(Person person, boolean empty) {
            if (person == null) {
                setGraphic(null);
            } else {
                firstNameLabel.setText(person.getFirstName());
                lastNameLabel.setText(person.getLastName());
                emailLabel.setText(person.getEmail());
                setGraphic(graphic);
            }
        }
    });
Comments