Have been struggling with this one.
I'd like the lists cells to be limited to the width of the parent ListView, and for the containing text to show ellipsis dots if the text is clipped/overrunning.
But no-matter what I do, the width of all the cells grows to the length of the longest text in those cells. And the text in the overrunning cell(s) is 'clipped' rather than what I want which is the ellipsis dots.
My ListView is defined in fxml:
<BorderPane fx:id="listViewResultsParentPane">
<center>
<ListView fx:id="listViewResults"/>
</center>
</BorderPane>
And I have a list cell class:
public class ResultsListCell extends ListCell<ResultsListItem> {
@Override
public void updateItem(final ResultsListItem item, final boolean empty) {
super.updateItem(item, empty);
if(empty || item == null){
setText("");
} else {
setText(item.title);
setTextOverrun(OverrunStyle.ELLIPSIS);
setEllipsisString("...");
}
}
}
And to get rid of the horizontal scrollbar, I'm using this css:
.list-view#listViewResults .scroll-bar:horizontal .increment-arrow,
.list-view#listViewResults .scroll-bar:horizontal .decrement-arrow,
.list-view#listViewResults .scroll-bar:horizontal .increment-button,
.list-view#listViewResults .scroll-bar:horizontal .decrement-button {
-fx-padding:0;
}
To set/limit the width of the cells I have tried:
Any help would be appreciated.
Solution
Bind the width of each cell to the preferred width of the list, less a couple of pixels to allow for the list borders. And set the max width of each cell to its preferred size:
prefWidthProperty().bind(list.widthProperty().subtract(2));
setMaxWidth(Control.USE_PREF_SIZE);
You don't need any custom CSS to remove the horizontal scroll bar. The horizontal scroll bar will only be shown if a displayed list cell exceeds the width of the ListView and the constraints specified above ensure that will never occur. You also don't need to set the text overrun style and the ellipsis string for the cell, as those will already be set to values you want by default.
Complete Sample Program
import javafx.application.Application;
import javafx.collections.*;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.stage.Stage;
public class ElidedListView extends Application {
@Override
public void start(Stage stage) {
ListView<String> list = new ListView<>();
ObservableList<String> items = FXCollections.observableArrayList(
"Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
"Aenean nibh ipsum, semper nec ipsum quis, dignissim gravida arcu.",
"Sed posuere auctor magna vel suscipit.",
"Aenean eu diam at dolor auctor porta.",
"Integer tincidunt ex metus, in euismod velit facilisis in.",
"Praesent purus mi, mattis rutrum egestas vitae, elementum vel dolo"
);
list.setItems(items);
list.setCellFactory(param -> new ListCell<String>() {
{
prefWidthProperty().bind(list.widthProperty().subtract(2));
setMaxWidth(Control.USE_PREF_SIZE);
}
@Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (item != null && !empty) {
setText(item);
} else {
setText(null);
}
}
});
stage.setScene(new Scene(list));
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
A way simpler and better solution is it to set the preferred width of the list cell to 0. The list cell will be resized to viewport width of the list anyway, but it won't be wider than the available space. This effectively hides the horizontal scrollbar, reacts correctly with/without vertical scrollbar and does not need any bindings. (Only exception is a list cell that has a computed minimal width higher than the listview width)
list.setCellFactory(l -> new ListCell<String>() {
{ // constructor
setPrefWidth(0); // avoids the issues
}
@Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
// do whatever you like
}
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With