Trần Trọng Tín Trần Trọng Tín - 11 days ago 8
CSS Question

Dynamically change ListCell's width of ListView in JavaFX

this is the interface of a chat app using javaFX. The chat window is a ListView component and I'm using CSS to polish it a little bit. Here are the CSS and the screenshot:
enter image description here

.list-cell {
display: inline-block;
-fx-min-width: 50px;
-fx-background-color: lightyellow;
-fx-background-radius: 30px;
-fx-border-radius: 20px;
-fx-border-width: 2px;
-fx-border-style: solid;
-fx-border-color: #666666;
}
.list-cell:empty {
-fx-background-color: transparent;
-fx-border-width: 0px;
}


The problem is that I want to change the width of each listCell depending on the length of text. I've tried to set
minWidth
prefWidth
(for example 50px) in the CSS file or using
listView.setCellFactory
but nothing happens. The length does not change at all. I wonder that can I change the length of each cell in a listView like that or not (or in order to do that I must use something like an HBox/VBox/seperator...)

Answer

Use a cell factory that sets the graphic to a Label, and style the label. E.g.:

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.stage.Stage;

public class FormattedListCell extends Application {

    @Override
    public void start(Stage primaryStage) {
        ListView<String> listView = new ListView<>();
        listView.getItems().addAll("One", "Two", "Three", "Four");

        listView.setCellFactory(lv -> new ListCell<String>() {
            private final Label label = new Label();
            @Override
            protected void updateItem(String item, boolean empty) {
                super.updateItem(item, empty);
                if (empty) {
                    setGraphic(null);
                } else {
                    label.setText(item);
                    setGraphic(label);
                }
            }
        });

        Scene scene = new Scene(listView, 400, 400);
        scene.getStylesheets().add("formatted-list-cell.css");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

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

and modify the stylesheet:

.list-cell .label {
  display: inline-block;
  -fx-min-width: 50px;
  -fx-background-color: lightyellow;
  -fx-background-radius: 30px;
  -fx-border-radius: 20px;
  -fx-border-width: 2px;
  -fx-border-style: solid;
  -fx-border-color: #666666;
}
.list-cell:empty .label {
  -fx-background-color: transparent;
  -fx-border-width: 0px;
}

You may need to actually style the list cell (as well as the label inside it) to get the exact style you want, but this should get you started.

enter image description here

Here is a more complete CSS file, which uses -fx-background so that the text color will automatically adjust, manages the selection color, and also adds some styles to the list cell itself:

.list-cell {
    -fx-background-color: transparent ;
    -fx-padding: 0 ;
}

.list-cell .label {
  display: inline-block;
  -fx-background: lightyellow;
  -fx-background-color: -fx-background ;
  -fx-background-radius: 30px;
  -fx-border-radius: 20px;
  -fx-border-width: 2px;
  -fx-border-style: solid;
  -fx-border-color: #666666;
  -fx-padding: 12px ;
}
.list-cell:empty .label {
  -fx-background-color: transparent;
  -fx-border-width: 0px;
}
.list-cell:selected .label {
    -fx-background: -fx-selection-bar ;
}

enter image description here